diff options
| author | 2023-06-11 19:29:30 +0200 | |
|---|---|---|
| committer | 2023-06-11 19:29:30 +0200 | |
| commit | 1139df03b0edbf08deb9aa26ade3776be3c1e180 (patch) | |
| tree | 0777ca13c5ae2e12064758f7fd20c78b80fa366b | |
| parent | 5ac04c7a3ec11d939a3773876b6924e1ae39f1a5 (diff) | |
remove RPARAM, add Oparam, lower args/rets to abi regs in abi0
| -rw-r--r-- | abi0.c | 250 | ||||
| -rw-r--r-- | amd64/emit.c | 94 | ||||
| -rw-r--r-- | amd64/isel.c | 26 | ||||
| -rw-r--r-- | amd64/sysv.c | 13 | ||||
| -rw-r--r-- | common.h | 13 | ||||
| -rw-r--r-- | ir.c | 3 | ||||
| -rw-r--r-- | ir.h | 13 | ||||
| -rw-r--r-- | irdump.c | 11 | ||||
| -rw-r--r-- | op.def | 2 | ||||
| -rw-r--r-- | parse.c | 14 | ||||
| -rw-r--r-- | regalloc.c | 26 | ||||
| -rw-r--r-- | test/test3.c | 5 |
12 files changed, 267 insertions, 203 deletions
@@ -18,11 +18,11 @@ abiret(struct abiarg abiret[2], struct abiargsvec *abiargs, int *ni, union irtyp if (retty.isagg) { retreg = mctarg->abiret(r, cls, ni, retty); if (!retreg) { - vpush(abiargs, ((struct abiarg) { {.cls = KPTR}, r[1] })); + vpush(abiargs, ((struct abiarg) { cls2type(KPTR), .stk = r[1] })); if (r[0] == -1) { memset(abiret, 0, 2*sizeof *abiret); } else { - abiret[0].ty = (union irtype) {.cls = KPTR}; + abiret[0].ty = cls2type(KPTR); abiret[0].reg = r[0]; } } @@ -31,7 +31,7 @@ abiret(struct abiarg abiret[2], struct abiargsvec *abiargs, int *ni, union irtyp assert(retreg == 1); } for (int i = 0; i < retreg; ++i) { - abiret[i].ty = (union irtype) {.cls = cls[i]}; + abiret[i].ty = cls2type(cls[i]); abiret[i].reg = r[i]; } return retreg; @@ -43,65 +43,88 @@ abiarg(struct abiargsvec *abiargs, int *ni, int *nf, int *ns, union irtype ty) short r[2]; uchar cls[2]; int ret = mctarg->abiarg(r, cls, ni, nf, ns, ty); - if (!ret) { /* aggregate in stack */ - vpush(abiargs, ((struct abiarg) { ty, -1 })); + if (!ret) { /* in stack */ + vpush(abiargs, ((struct abiarg) { ty, .stk = r[0] })); } else if (ret == 1 && ty.isagg && cls[0] == KPTR) { /* aggregate by pointer */ - vpush(abiargs, ((struct abiarg) { {.cls = cls[0]}, r[0] })); - } else { - vpush(abiargs, ((struct abiarg) { {.cls = cls[0]}, r[0] })); + vpush(abiargs, ((struct abiarg) { cls2type(cls[0]), .reg = r[0] })); + } else { /* by regs */ + vpush(abiargs, ((struct abiarg) { cls2type(cls[0]), .reg = r[0] })); if (ret == 2) - vpush(abiargs, ((struct abiarg) { {.cls = cls[1]}, r[1] })); + vpush(abiargs, ((struct abiarg) { cls2type(cls[1]), .reg = r[1] })); } return ret; } -/* RPARAM can only appear in the entry block (prologue), each RARG can only appear once. - * this function patches param starting at instruction no. *start according to cls - * to patch it to use arg no. `to' (and maybe also `to + 1') */ +static struct instr +copyparam(struct abiarg abi) +{ + if (abi.reg >= 0) { /* reg */ + assert(!abi.ty.isagg); + return mkinstr(Ocopy, abi.ty.cls, mkref(RREG, abi.reg)); + } else if (!abi.ty.isagg) { /* scalar in stack */ + enum op ld; + if (abi.ty.cls == KPTR) abi.ty.cls = siz2intcls[cls2siz[abi.ty.cls]]; + switch (abi.ty.cls) { + default: assert(0); + case KI4: ld = Oloadu4; break; + case KI8: ld = Oloadi8; break; + case KF4: ld = Oloadf4; break; + case KF8: ld = Oloadf8; break; + } + vpush(&addrtab, ((struct addr) {.base = mkref(RREG, mctarg->spr), .disp = abi.reg})); + return mkinstr(ld, abi.ty.cls, mkref(RMORE, addrtab.n - 1)); + } else { /* aggregate in stack */ + vpush(&addrtab, ((struct addr) {.base = mkref(RREG, mctarg->spr), .disp = abi.reg})); + return mkinstr(Ocopy, KPTR, mkref(RMORE, addrtab.n - 1)); + } +} + static void -patchparam(struct function *fn, int *start, int param, int tydat, int to, struct abiarg abi[2]) +patchparam(struct function *fn, int *curi, int param, int tydat, int nabi, struct abiarg abi[2]) { struct block *blk = fn->entry; - assert(!blk->phi.n); - while((*start)++ < blk->ins.n) { - struct instr *ins = &instrtab[blk->ins.p[*start - 1]]; - if (ins->op == Ocopy && ins->l.t == RPARAM && ins->l.i == param) { - /* originally aggregate argument */ - assert(tydat != -1); - if (abi[0].ty.isagg /* aggregate in stack */ - || abi[0].ty.cls == KPTR) /* aggregate by pointer */ - { - ins->l.i = to; - } else { /* aggregate in registers */ - const struct typedata *td = &typedata[tydat]; - /* transform - * %x = copy %argX - * into - * %x = alloca... - * store* %x, %argN - * store* %x + I, %argM - */ - assert(td->siz <= 16 && td->align <= 16); - ins->op = Oalloca8 + (td->align == 16); - ins->l = mkref(RICON, td->align == 16 ? 1 : td->siz / 8); - insertinstr(blk, *start, mkinstr(Ostore1 + ilog2(cls2siz[abi[0].ty.cls]), 0, - mkref(RTMP, ins - instrtab), mkref(RPARAM, to))); - *start += 1; - if (td->siz > 8) { - struct instr tmp = mkinstr(Oadd, KPTR, - mkref(RTMP, ins - instrtab), mkref(RICON, cls2siz[abi[0].ty.cls])); - insertinstr(blk, *start+1, mkinstr(Ostore1 + ilog2(cls2siz[abi[1].ty.cls]), 0, - insertinstr(blk, *start, tmp), mkref(RPARAM, to+1))); - *start += 2; - } + assert(in_range(nabi,1,2)); + + for (; *curi < blk->ins.n; ++*curi) { + struct instr *ins = &instrtab[blk->ins.p[*curi]]; + if (ins->op != Oparam) continue; + assert(ins->l.t == RICON && ins->l.i == param); + assert(ins->r.t == RTYPE + && ins->r.i == (tydat < 0 ? abi[0].ty : (union irtype){.isagg=1, .dat=tydat}).bits); + if (abi[0].ty.isagg || tydat < 0) { + /* aggregate in stack or scalar, just copy */ + assert(nabi == 1); + *ins = copyparam(abi[0]); + } else { /* aggregate in registers, materialize */ + union ref alloc, r[2]; + struct instr st; + const struct typedata *td; + uint nalloc; + + assert(tydat >= 0); + td = &typedata[tydat]; + assert(td->siz <= 16 && td->align <= 16); + nalloc = td->align == 16 ? 1 : td->siz/8 + (td->siz%8 != 0); + *ins = mkinstr(Oalloca8 + (td->align==16), KPTR, mkref(RICON, nalloc)); + alloc = mkref(RTMP, ins - instrtab); + r[0] = insertinstr(blk, ++*curi, copyparam(abi[0])); + if (nabi > 1) r[1] = insertinstr(blk, ++*curi, copyparam(abi[1])); + /* transform + * %x = copy %p + * into + * %x = alloca... + * store* %x, %a + * store* %x + N, %b + */ + st = mkinstr(Ostore1 + ilog2(cls2siz[abi[0].ty.cls]), 0, alloc, r[0]); + insertinstr(blk, ++*curi, st); + if (nabi > 1) { + struct instr tmp = mkinstr(Oadd, KPTR, alloc, mkref(RICON, cls2siz[abi[0].ty.cls])); + st = mkinstr(Ostore1 + ilog2(cls2siz[abi[1].ty.cls]), 0, insertinstr(blk, ++*curi, tmp), r[1]); + insertinstr(blk, ++*curi, st); } - break; - } else if (oisstore(ins->op) && ins->r.t == RPARAM && ins->r.i == param) { - /* normal scalar argument */ - assert(tydat == -1); - ins->r.i = to; - break; } + break; } } @@ -117,6 +140,10 @@ patcharg(struct block *blk, int *icall, struct call *call, if (abi[0].ty.isagg /* aggregate in stack */ || abi[0].ty.cls == KPTR) /* aggregate by pointer */ { + Single: + if (abi[0].reg >= 0) + *arg = mkinstr(Omove, abi[0].ty.isagg ? KPTR : abi[0].ty.cls, + mkref(RREG, abi[0].reg), arg->r); return 1; } else { /* aggregate in registers */ union ref src = arg->r; @@ -148,10 +175,8 @@ patcharg(struct block *blk, int *icall, struct call *call, *icall += arginst - (call->narg - argidx); return nabi; } - } else { - /* normal scalar argument */ - return 1; - } + } else /* normal scalar argument */ + goto Single; } void @@ -164,16 +189,17 @@ abi0(struct function *fn) int rvovar = -1; int ni = 0, nf = 0, ns = 0, istart = 0; struct block *blk; - union ref sret; + union ref sret = {0}; bool sretarghidden = 0; if (fn->retty.t == TYVOID) { fn->nabiret = 0; } else { fn->nabiret = abiret(fn->abiret, &abiargs, &ni, mkirtype(fn->retty)); - if (!fn->nabiret && isagg(fn->retty)) { /* ret by hidden pointer */ + if (!fn->nabiret && isagg(fn->retty)) { /* ret agg by hidden pointer */ + struct instr param = copyparam(abiargs.p[0]); sretarghidden = ni == 0; - sret = insertinstr(fn->entry, 0, mkinstr(Ocopy, KPTR, mkref(RPARAM, 0))); + sret = insertinstr(fn->entry, 0, param); ++istart; } } @@ -181,11 +207,9 @@ abi0(struct function *fn) /* adjust params */ for (int i = 0; i < nparam; ++i) { union irtype pty = mkirtype(paramty[i]); - int thisi = sretarghidden + ni + nf + ns; int first = abiargs.n; int ret = abiarg(&abiargs, &ni, &nf, &ns, pty); - if (i != thisi || (pty.isagg && ret)) - patchparam(fn, &istart, i, pty.isagg ? pty.dat : -1, thisi, &abiargs.p[first]); + patchparam(fn, &istart, i, pty.isagg ? pty.dat : -1, ret+!ret, &abiargs.p[first]); } fn->abiarg = alloccopy(&fn->arena, abiargs.p, abiargs.n * sizeof *abiargs.p, 0); fn->nabiarg = abiargs.n; @@ -219,81 +243,86 @@ abi0(struct function *fn) do { /* adjust calls */ for (int iinstr = 0; iinstr < blk->ins.n; ++iinstr) { + union ref retmem; struct instr *ins = &instrtab[blk->ins.p[iinstr]]; struct call *call = &calltab.p[ins->r.i]; - bool structbyval; - int vararg; + int vararg, nret = 0; if (ins->op != Ocall) continue; vararg = call->vararg; vinit(&abiargs, abiargsbuf, arraylength(abiargsbuf)); - if (!(structbyval = call->ret.isagg)) - for (int i = iinstr - call->narg; i < iinstr; ++i) - if ((structbyval = ref2type(instrtab[blk->ins.p[i]].l).isagg)) - break; - ni = nf = ns = 0; - memset(call->abiret, 0, sizeof call->abiret); + assert(!ins->cls == !call->ret.bits); + nret = abiret(call->abiret, &abiargs, &ni, call->ret); if (call->ret.isagg) { /* adjust struct return */ - union ref temp; union irtype retty = call->ret; struct instr alloca = { .cls = KPTR }; struct typedata *td = &typedata[retty.dat]; - int ret = abiret(call->abiret, &abiargs, &ni, retty); sretarghidden = ni == 0; alloca.op = Oalloca8 + (td->align == 16); alloca.l = mkref(RICON, td->align == 16 ? 1 : td->siz / 8); - temp = insertinstr(blk, iinstr++ - call->narg, alloca); - replref(fn, blk, iinstr, mkref(RTMP, ins - instrtab), temp); - if (!ret) { /* hidden pointer argument */ + retmem = insertinstr(blk, iinstr++ - call->narg, alloca); + if (!nret) /* hidden pointer argument */ insertinstr(blk, iinstr++ - call->narg, - mkarginstr((union irtype){.cls = KPTR}, temp)); - ins->cls = 0; + mkinstr(Omove, KPTR, mkref(RREG, call->abiret[0].reg), retmem)); + } + + /* adjust args */ + for (int i = 0, i2 = ni + sretarghidden; i < call->narg; ++i) { + union irtype pty = ref2type(instrtab[blk->ins.p[iinstr - call->narg + i]].l); + int first = abiargs.n; + int ret = abiarg(&abiargs, &ni, &nf, &ns, pty); + ret = patcharg(blk, &iinstr, call, i, ret, &abiargs.p[first]); + if (call->vararg == i) vararg = i2; + i2 += ret; + } + /* adjust return */ + if (!call->ret.isagg) { + /* duplicate to reuse same TMP ref */ + ins->cls = 0; + insertinstr(blk, iinstr++, *ins); + /* now ins will be Ocopy <reg> */ + } + if (call->ret.isagg) { + replref(fn, blk, iinstr, mkref(RTMP, ins - instrtab), retmem); + if (!nret) { /* hidden pointer argument */ + if (call->abiret[0].reg >= 0) + ++nret; } else { /* aggregate returned in regs */ - union ref call2r; - int to = iinstr + 1; - assert(in_range(ret, 1, 2)); - ins->cls = call->abiret[0].ty.cls; - if (ret == 2) - call2r = insertinstr(blk, to++, mkinstr(Ocall2r, call->abiret[1].ty.cls, - mkref(RTMP, ins - instrtab))); - for (int i = 0; i < ret; ++i) { - uchar cls; + union ref r[2]; + struct instr ins; + assert(in_range(nret, 1, 2)); + ins = mkinstr(Ocopy, call->abiret[0].ty.cls, mkref(RREG, call->abiret[0].reg)); + r[0] = insertinstr(blk, ++iinstr, ins); + if (nret == 2) { + ins = mkinstr(Ocopy, call->abiret[1].ty.cls, mkref(RREG, call->abiret[1].reg)); + r[1] = insertinstr(blk, ++iinstr, ins); + } + for (int i = 0; i < nret; ++i) { struct instr store = {0}; /* XXX this can generate unaligned stores */ - switch (cls = call->abiret[i].ty.cls) { + switch (call->abiret[i].ty.cls) { default: assert(0); case KF4: case KI4: store.op = Ostore4; break; case KI8: case KF8: store.op = Ostore8; break; } if (i == 0) { - store.l = temp; - store.r = mkref(RTMP, ins - instrtab); + store.l = retmem; } else { - store.l = insertinstr(blk, to++, - mkinstr(Oadd, KPTR, temp, + store.l = insertinstr(blk, ++iinstr, + mkinstr(Oadd, KPTR, retmem, mkref(RICON, cls2siz[call->abiret[0].ty.cls]))); - store.r = call2r; } - insertinstr(blk, to++, store); + store.r = r[i]; + insertinstr(blk, ++iinstr, store); } } - } else if (ins->cls) { - int ret = abiret(call->abiret, &abiargs, &ni, (union irtype){.cls = ins->cls}); - assert(ret == 1 && !ni); + } else if (call->ret.cls) { + *ins = mkinstr(Ocopy, call->abiret[0].ty.cls, mkref(RREG, call->abiret[0].reg)); } - for (int i = 0; i < call->narg; ++i) { - union irtype pty = ref2type(instrtab[blk->ins.p[iinstr - call->narg + i]].l); - int thisi = sretarghidden + ni + nf + ns; - int first = abiargs.n; - int ret = abiarg(&abiargs, &ni, &nf, &ns, pty); - ret = patcharg(blk, &iinstr, call, i, ret, &abiargs.p[first]); - if (call->vararg == i) - vararg = thisi; - } if (call->ret.isagg) call->ret = (union irtype){0}; call->vararg = vararg; call->abiargregs = alloc(&fn->arena, abiargs.n * sizeof *call->abiargregs, 0); @@ -338,6 +367,19 @@ abi0(struct function *fn) else memset(blk->jmp.arg, 0, sizeof blk->jmp.arg); } } + 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); + } + memset(blk->jmp.arg, 0, sizeof blk->jmp.arg); + } + } } while ((blk = blk->lnext) != fn->entry); if (ccopt.dbg.a) { 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}}, @@ -96,11 +96,14 @@ struct option { bool pedant; bool trigraph; bool nocolor; - struct { - bool p : 1, /* after parsing */ - a : 1, /* after abi0 */ - i : 1, /* after isel */ - r : 1; /* after regalloc */ + union { + struct { + bool p : 1, /* after parsing */ + a : 1, /* after abi0 */ + i : 1, /* after isel */ + r : 1; /* after regalloc */ + }; + uchar any; } dbg; }; extern struct option ccopt; @@ -381,7 +381,8 @@ irfini(struct function *fn) abi0(fn); mctarg->isel(fn); regalloc(fn); - mctarg->emit(fn); + if (!ccopt.dbg.any) + mctarg->emit(fn); } freefn(fn); @@ -45,7 +45,10 @@ struct xcon { struct abiarg { union irtype ty; - short reg; /* -1 -> stack */ + union { + short reg; /* >= 0 */ + short stk; /* < 0 */ + }; }; struct call { @@ -66,7 +69,6 @@ enum refkind { RNONE, RTMP, /* reference to another instruction's result */ RREG, /* machine register */ - RPARAM, /* function param */ RICON, /* small integer constants */ RXCON, /* other constants (incl. external symbols) */ RMORE, /* Ocall -> calltab idx, Ophi -> phitab idx, else -> addrtab idx */ @@ -140,6 +142,7 @@ struct function { struct mctarg { short gpr0, /* first gpr */ ngpr, /* gpr count */ + spr, /* stack pointer reg */ fpr0, /* first fpr */ nfpr; /* fpr count */ struct bitset rcallee[1], /* callee-saved */ @@ -159,8 +162,9 @@ struct mctarg { * r & cls filled with reg and irclass of each scalar arg * if reg == -1 -> stack * big struct -> returns 0, - * if passed in stack cls[0] == 0, r[0] == -1 - * if passed by pointer cls[0] == KPTR, r[0] contains integer register or -1 if stack + * if passed in stack cls[0] == 0, r[0] == negative SP offset + * if passed by pointer cls[0] == KPTR, r[0] contains integer register + * or negative SP offset if stack */ int (*abiarg)(short r[2], uchar cls[2], int *ni, int *nf, int *ns, union irtype); @@ -188,6 +192,7 @@ extern struct addrtab {vec_of(struct addr);} addrtab; #define mkarginstr(ty, x) mkinstr(Oarg, 0, mktyperef(ty), (x)) void irinit(struct function *); void irfini(struct function *); +#define cls2type(k) ((union irtype){.cls=(k)}) union irtype mkirtype(union type); union ref mkintcon(struct function *, enum irclass, vlong); union ref mkfltcon(struct function *, enum irclass, double); @@ -84,7 +84,6 @@ dumpref(enum op o, union ref ref) case RREG: efmt("%s", mctarg->rnames[ref.i]); break; - case RPARAM: efmt("%%param%d", ref.i); break; case RICON: if (o == Ointrin) efmt("\"%s\"", intrinname[ref.i]); else efmt("%d", ref.i); @@ -129,7 +128,9 @@ dumpref(enum op o, union ref ref) efmt(" * %d", 1<<addr->shift); k = 1; } - if (k && addr->disp) efmt(" + %d", addr->disp); + if (k && addr->disp) { + efmt(" %c %d", "-+"[addr->disp > 0], addr->disp < 0 ? -addr->disp : addr->disp); + } assert(k); efmt("]"); } @@ -212,10 +213,6 @@ dumpblk(struct function *fn, struct block *blk) for (i = 0; i < 2; ++i) { if (!blk->jmp.arg[i].t) break; if (i > 0) efmt(", "); - if (blk->jmp.t == Jret && fn->nabiret > i) { - prityp(fn->abiret[i].ty); - efmt(" "); - } dumpref(0, blk->jmp.arg[i]); } if (i && blk->s1) efmt(", "); @@ -237,7 +234,7 @@ irdump(struct function *fn, const char *fname) efmt("abi: ("); for (int i = 0; i < fn->nabiarg; ++i) { if (i > 0) efmt(", "); - if (fn->abiarg[i].reg != -1) { + if (fn->abiarg[i].reg >= 0) { efmt("%s", mctarg->rnames[fn->abiarg[i].reg]); } else { prityp(fn->abiarg[i].ty); @@ -62,8 +62,8 @@ _(store1, 2) _(store2, 2) _(store4, 2) _(store8, 2) +_(param, 2) _(arg, 2) _(call, 2) -_(call2r, 1) _(intrin, 2) _(phi, 1) @@ -1797,6 +1797,16 @@ function(struct parser *pr, struct function *fn, const char **pnames, const stru const bool doemit = fn->curblk; struct env e; envdown(pr, &e); + + /* emit Oparam instructions */ + EMITS { + for (int i = 0; i < td->nmemb; ++i) { + union irtype pty = mkirtype(td->param[i]); + union ref r = addinstr(fn, mkinstr(Oparam, pty.isagg ? KPTR : pty.cls, + mkref(RICON, i), mktyperef(pty))); + assert(r.t == RTMP && r.i == i); + } + } /* add parameters to symbol table and create prologue (arguments) block */ for (int i = 0; i < td->nmemb; ++i) { if (pnames[i]) { @@ -1805,9 +1815,9 @@ function(struct parser *pr, struct function *fn, const char **pnames, const stru EMITS { if (isscalar(arg.ty)) { arg.id = addinstr(fn, mkalloca(typesize(arg.ty), typealign(arg.ty))).i; - genstore(fn, arg.ty, mkref(RTMP, arg.id), mkref(RPARAM, i)); + genstore(fn, arg.ty, mkref(RTMP, arg.id), mkref(RTMP, i)); } else { - arg.id = addinstr(fn, mkinstr(Ocopy, KPTR, mkref(RPARAM, i))).i; + arg.id = addinstr(fn, mkinstr(Ocopy, KPTR, mkref(RTMP, i))).i; } } putdecl(pr, &arg); @@ -1,7 +1,7 @@ #include "ir.h" -static struct bitset taken[1]; static struct bitset globusage[1]; +static struct bitset taken[1]; static void def(struct instr *ins) @@ -64,15 +64,7 @@ use(struct block *blk, enum op op, int hint, union ref *ref) /* result of comparison instr is only used to conditionally branch, * doesn't usually need a reg (handled by isel) */ return; - if (ins->op == Ocall) { - struct call *call = &calltab.p[ins->r.i]; - hint = call->abiret[0].reg; - } else if (ins->op == Ocall2r) { - struct instr *ins2 = &instrtab[ins->l.i]; - struct call *call = &calltab.p[ins2->r.i]; - assert(ins->l.t == RTMP && ins2->op == Ocall); - hint = call->abiret[0].reg; - } + assert(ins->op != Ocall); if (hint != -1 && !bstest(taken, hint)) { take(hint); ins->reg = hint + 1; @@ -129,22 +121,14 @@ regalloc(struct function *fn) continue; } def(ins); - if (ins->op != Ocall) { + if (ins->op == Omove) { + use(blk, ins->op, ins->l.i, &ins->r); + } else if (ins->op != Ocall) { if (ins->op == Ocopy) hint0 = ins->reg - 1; if (ins->l.t) use(blk, ins->op, hint0, &ins->l); if (ins->r.t) use(blk, ins->op, hint1, &ins->r); } else { struct call *call = &calltab.p[ins->r.i]; - for (int iarg = 0; iarg < call->narg; ++iarg) { - struct instr *arg = &instrtab[blk->ins.p[i - call->narg + iarg]]; - int reg = call->abiargregs[iarg]; - assert(arg->op == Oarg); - if (reg != -1) { - assert(!bstest(taken, reg) && "nyi spill"); - arg->reg = reg + 1; - take(reg); - } - } use(blk, ins->op, hint0, &ins->l); } } diff --git a/test/test3.c b/test/test3.c index e6599bb..35e5e8b 100644 --- a/test/test3.c +++ b/test/test3.c @@ -19,5 +19,10 @@ double ff(double x, double y) return x + y + .5; } +void testss() { + extern struct { long x,y; } aa(); + long x = aa().x; +} + long fma(long x, long y) { return x + (y <<1) - 2147483648;} |