aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2023-06-11 19:29:30 +0200
committerlemon <lsof@mailbox.org>2023-06-11 19:29:30 +0200
commit1139df03b0edbf08deb9aa26ade3776be3c1e180 (patch)
tree0777ca13c5ae2e12064758f7fd20c78b80fa366b
parent5ac04c7a3ec11d939a3773876b6924e1ae39f1a5 (diff)
remove RPARAM, add Oparam, lower args/rets to abi regs in abi0
-rw-r--r--abi0.c250
-rw-r--r--amd64/emit.c94
-rw-r--r--amd64/isel.c26
-rw-r--r--amd64/sysv.c13
-rw-r--r--common.h13
-rw-r--r--ir.c3
-rw-r--r--ir.h13
-rw-r--r--irdump.c11
-rw-r--r--op.def2
-rw-r--r--parse.c14
-rw-r--r--regalloc.c26
-rw-r--r--test/test3.c5
12 files changed, 267 insertions, 203 deletions
diff --git a/abi0.c b/abi0.c
index 3547f64..0e8b551 100644
--- a/abi0.c
+++ b/abi0.c
@@ -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}},
diff --git a/common.h b/common.h
index 11741de..e31d48b 100644
--- a/common.h
+++ b/common.h
@@ -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;
diff --git a/ir.c b/ir.c
index e8a7173..28391ad 100644
--- a/ir.c
+++ b/ir.c
@@ -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);
diff --git a/ir.h b/ir.h
index bdace5e..1c8468b 100644
--- a/ir.h
+++ b/ir.h
@@ -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);
diff --git a/irdump.c b/irdump.c
index 1bd8cff..5ee817a 100644
--- a/irdump.c
+++ b/irdump.c
@@ -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);
diff --git a/op.def b/op.def
index 706f308..8bdfbbc 100644
--- a/op.def
+++ b/op.def
@@ -62,8 +62,8 @@ _(store1, 2)
_(store2, 2)
_(store4, 2)
_(store8, 2)
+_(param, 2)
_(arg, 2)
_(call, 2)
-_(call2r, 1)
_(intrin, 2)
_(phi, 1)
diff --git a/parse.c b/parse.c
index e97c46a..b488b36 100644
--- a/parse.c
+++ b/parse.c
@@ -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);
diff --git a/regalloc.c b/regalloc.c
index ccec452..f887c59 100644
--- a/regalloc.c
+++ b/regalloc.c
@@ -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;}