aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--abi0.c86
-rw-r--r--amd64/isel.c62
-rw-r--r--ir.h2
-rw-r--r--irdump.c5
-rw-r--r--op.def1
-rw-r--r--regalloc.c2
6 files changed, 101 insertions, 57 deletions
diff --git a/abi0.c b/abi0.c
index 19a5dff..8523c99 100644
--- a/abi0.c
+++ b/abi0.c
@@ -56,14 +56,15 @@ abiarg(struct abiargsvec *abiargs, int *ni, int *nf, int *ns, union irtype ty)
}
static struct instr
-copyparam(struct abiarg abi)
+copyparam(struct function *fn, int *curi, int param, struct abiarg abi)
{
- struct addr addr = {.base = mkref(RREG, mctarg->bpr), .disp = -abi.stk};
+ struct instr par = mkinstr(Oparam, abi.ty.cls, mkref(RICON, param), mktyperef(abi.ty));
if (abi.reg >= 0) { /* reg */
assert(!abi.ty.isagg);
- return mkinstr(Ocopy, abi.ty.cls, mkref(RREG, abi.reg));
+ return par;
} else if (!abi.ty.isagg) { /* scalar in stack */
enum op ld;
+ par.cls = KPTR;
if (abi.ty.cls == KPTR) abi.ty.cls = siz2intcls[cls2siz[abi.ty.cls]];
switch (abi.ty.cls) {
default: assert(0);
@@ -72,14 +73,15 @@ copyparam(struct abiarg abi)
case KF4: ld = Oloadf4; break;
case KF8: ld = Oloadf8; break;
}
- return mkinstr(ld, abi.ty.cls, mkaddr(addr));
+ return mkinstr(ld, abi.ty.cls, insertinstr(fn->entry, (*curi)++, par));
} else { /* aggregate in stack */
- return mkinstr(Ocopy, KPTR, mkaddr(addr));
+ par.cls = KPTR;
+ return par;
}
}
static void
-patchparam(struct function *fn, int *curi, int param, int tydat, int nabi, 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(in_range(nabi,1,2));
@@ -87,13 +89,12 @@ patchparam(struct function *fn, int *curi, int param, int tydat, int nabi, struc
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]);
+ *ins = copyparam(fn, curi, *param, abi[0]);
} else { /* aggregate in registers, materialize */
union ref alloc, r[2];
struct instr st;
@@ -106,8 +107,9 @@ patchparam(struct function *fn, int *curi, int param, int tydat, int nabi, struc
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]));
+ r[0] = insertinstr(blk, ++*curi, copyparam(fn, NULL, *param, abi[0]));
+ if (nabi > 1)
+ r[1] = insertinstr(blk, ++*curi, copyparam(fn, NULL, ++*param, abi[1]));
/* transform
* %x = copy %p
* into
@@ -123,6 +125,8 @@ patchparam(struct function *fn, int *curi, int param, int tydat, int nabi, struc
insertinstr(blk, ++*curi, st);
}
}
+ ++*param;
+ ++*curi;
break;
}
}
@@ -139,10 +143,6 @@ 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;
@@ -175,7 +175,7 @@ patcharg(struct block *blk, int *icall, struct call *call,
return nabi;
}
} else /* normal scalar argument */
- goto Single;
+ return 1;
}
static struct abiarg abiargsbuf[32];
@@ -205,7 +205,7 @@ abi0_call(struct function *fn, struct instr *ins, struct block *blk, int *curi)
retmem = insertinstr(blk, (*curi)++ - call->narg, alloca);
if (!nret) /* hidden pointer argument */
insertinstr(blk, (*curi)++ - call->narg,
- mkinstr(Omove, KPTR, mkref(RREG, abiargs.p[0].reg), retmem));
+ mkinstr(Oarg, 0, mktyperef((union irtype){.cls=KPTR}), retmem));
}
/* adjust args */
@@ -218,31 +218,27 @@ abi0_call(struct function *fn, struct instr *ins, struct block *blk, int *curi)
i2 += ret;
}
/* adjust return */
- if (call->ret.bits && !call->ret.isagg) {
- /* duplicate to reuse same TMP ref */
- ins->cls = 0;
- insertinstr(blk, (*curi)++, *ins);
- /* now ins will be Ocopy <reg> */
- }
if (call->ret.isagg) {
replref(fn, blk, (*curi), mkref(RTMP, ins - instrtab), retmem);
+ ins->cls = 0;
if (!nret) { /* hidden pointer argument */
+ ins->cls = 0;
if (call->abiret[0].reg >= 0) {
- /* the result location pointer is also returned by the callee, like in x86 */
+ /* the result location pointer is also returned by the callee, e.g. in x86 */
+ ins->cls = KPTR;
++nret;
- insertinstr(blk, ++*curi, mkinstr(Ocopy, KPTR, mkref(RREG, call->abiret[0].reg)));
- /* even if this is not used it the register copy
+ /* even if this is not used, the register copy
* must be emitted for the register allocator to know */
}
} else { /* aggregate returned in regs */
union ref r[2];
- struct instr ins;
+ struct instr ret2;
assert(in_range(nret, 1, 2));
- ins = mkinstr(Ocopy, call->abiret[0].ty.cls, mkref(RREG, call->abiret[0].reg));
- r[0] = insertinstr(blk, ++*curi, ins);
+ ins->cls = call->abiret[0].ty.cls;
+ r[0] = mkref(RTMP, ins - instrtab);
if (nret == 2) {
- ins = mkinstr(Ocopy, call->abiret[1].ty.cls, mkref(RREG, call->abiret[1].reg));
- r[1] = insertinstr(blk, ++*curi, ins);
+ ret2 = mkinstr(Ocall2r, call->abiret[1].ty.cls, r[0]);
+ r[1] = insertinstr(blk, ++*curi, ret2);
}
for (int i = 0; i < nret; ++i) {
struct instr store = {0};
@@ -255,22 +251,19 @@ abi0_call(struct function *fn, struct instr *ins, struct block *blk, int *curi)
if (i == 0) {
store.l = retmem;
} else {
- store.l = insertinstr(blk, ++*curi,
- mkinstr(Oadd, KPTR, retmem,
- mkref(RICON, cls2siz[call->abiret[0].ty.cls])));
+ union ref off = mkref(RICON, cls2siz[call->abiret[0].ty.cls]);
+ struct instr addr = mkinstr(Oadd, KPTR, retmem, off);
+ store.l = insertinstr(blk, ++*curi, addr);
}
store.r = r[i];
insertinstr(blk, ++*curi, store);
}
}
- } else if (call->ret.cls) {
- *ins = mkinstr(Ocopy, call->abiret[0].ty.cls, mkref(RREG, call->abiret[0].reg));
}
if (call->ret.isagg) call->ret = (union irtype){0};
call->vararg = vararg;
- call->abiargregs = alloc(&fn->arena, abiargs.n * sizeof *call->abiargregs, 0);
- for (int i = 0; i < abiargs.n; ++i) call->abiargregs[i] = abiargs.p[i].reg;
+ call->abiarg = alloccopy(&fn->arena, abiargs.p, abiargs.n * sizeof(struct abiarg), 0);
call->narg = abiargs.n;
vfree(&abiargs);
}
@@ -291,18 +284,18 @@ abi0(struct function *fn)
} else {
fn->nabiret = abiret(fn->abiret, &abiargs, &ni, mkirtype(fn->retty));
if (!fn->nabiret && isagg(fn->retty)) { /* ret agg by hidden pointer */
- struct instr param = copyparam(abiargs.p[0]);
+ struct instr param = copyparam(fn, NULL, 0, abiargs.p[0]);
sret = insertinstr(fn->entry, 0, param);
++istart;
}
}
/* adjust params */
- for (int i = 0; i < nparam; ++i) {
+ for (int i = 0, param = 0; i < nparam; ++i) {
union irtype pty = mkirtype(paramty[i]);
int first = abiargs.n;
int ret = abiarg(&abiargs, &ni, &nf, &ns, pty);
- patchparam(fn, &istart, i, pty.isagg ? pty.dat : -1, ret+!ret, &abiargs.p[first]);
+ patchparam(fn, &istart, &param, 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;
@@ -377,19 +370,6 @@ 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/isel.c b/amd64/isel.c
index 10ff5ea..51b5ac1 100644
--- a/amd64/isel.c
+++ b/amd64/isel.c
@@ -93,6 +93,39 @@ fixarg(union ref *r, struct instr *ins, struct block *blk, int *curi)
}
}
+static void
+selcall(struct function *fn, struct instr *ins, struct block *blk, int *curi)
+{
+ const struct call *call = &calltab.p[ins->r.i];
+ int iarg = *curi - 1;
+ enum irclass cls;
+
+ for (int i = call->narg - 1; i >= 0; --i) {
+ struct instr *arg;
+ for (;;) {
+ assert(i >= 0 && "arg?");
+ if ((arg = &instrtab[blk->ins.p[iarg--]])->op == Oarg)
+ break;
+ }
+
+ if (call->abiarg[i].reg >= 0) {
+ assert(!call->abiarg[i].ty.isagg);
+ *arg = mkinstr(Omove, call->abiarg[i].ty.cls, mkref(RREG, call->abiarg[i].reg), arg->r);
+ }
+ }
+ cls = ins->cls;
+ ins->cls = 0;
+ if (cls) {
+ /* duplicate to reuse same TMP ref */
+ insertinstr(blk, (*curi)++, *ins);
+ *ins = mkinstr(Ocopy, cls, mkref(RREG, call->abiret[0].reg));
+ if (instrtab[blk->ins.p[*curi + 1]].op == Ocall2r) {
+ ins = &instrtab[blk->ins.p[++*curi]];
+ *ins = mkinstr(Ocopy, ins->cls, mkref(RREG, call->abiret[1].reg));
+ }
+ }
+}
+
#define isimm32(r) (concls(r) == KI4)
#define rswap(a,b) do { union ref _t = (a); (a) = (b); (b) = _t; } while (0)
@@ -202,9 +235,23 @@ sel(struct function *fn, struct instr *ins, struct block *blk, int *curi)
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));
+ *ins = mkinstr(Oadd, KPTR, mkref(RREG, RBP), mkref(RICON, -fn->stksiz));
break;
- case Ocall: case Ointrin:
+ case Oparam:
+ assert(ins->l.t == RICON && ins->l.i < fn->nabiarg);
+ if (fn->abiarg[ins->l.i].reg >= 0)
+ *ins = mkinstr(Ocopy, ins->cls, mkref(RREG, fn->abiarg[ins->l.i].reg));
+ else /* stack */
+ *ins = mkinstr(Oadd, KPTR, mkref(RREG, RBP), mkref(RICON, -fn->abiarg[ins->l.i].stk));
+ break;
+ case Oarg:
+ fixarg(&ins->r, ins, blk, curi);
+ break;
+ case Ocall:
+ selcall(fn, ins, blk, curi);
+ break;
+ case Ocall2r: assert(0);
+ case Ointrin:
break;
case Oshl: case Osar: case Oslr:
if (!iscon(ins->r)) {
@@ -332,6 +379,17 @@ seljmp(struct function *fn, struct block *blk)
blk->jmp.arg[0] = insertinstr(blk, blk->ins.n, mkinstr(Oneq, instrtab[c.i].cls, c, ZEROREF));
}
}
+ } else if (blk->jmp.t == Jret) {
+ if (blk->jmp.arg[0].t) {
+ union ref r = mkref(RREG, fn->abiret[0].reg);
+ insertinstr(blk, blk->ins.n, mkinstr(Omove, fn->abiret[0].ty.cls, r , blk->jmp.arg[0]));
+ blk->jmp.arg[0] = r;
+ if (blk->jmp.arg[1].t) {
+ r = mkref(RREG, fn->abiret[1].reg);
+ insertinstr(blk, blk->ins.n, mkinstr(Omove, fn->abiret[1].ty.cls, r, blk->jmp.arg[1]));
+ blk->jmp.arg[1] = r;
+ }
+ }
}
}
diff --git a/ir.h b/ir.h
index 72a0bd5..8208dea 100644
--- a/ir.h
+++ b/ir.h
@@ -54,7 +54,7 @@ struct call {
union irtype ret;
ushort narg;
short vararg; /* first variadic arg or -1 */
- short *abiargregs;
+ struct abiarg *abiarg;
struct abiarg abiret[2];
};
diff --git a/irdump.c b/irdump.c
index f1a64f5..c936638 100644
--- a/irdump.c
+++ b/irdump.c
@@ -203,6 +203,11 @@ dumpblk(struct function *fn, struct block *blk)
dumpinst(&instrtab[blk->ins.p[i]]);
}
efmt(" %s ", jnames[blk->jmp.t]);
+ if (blk->jmp.arg[0].t && !fn->nabiret && isagg(fn->retty)) {
+ /* un-lowered struct return */
+ dumpref(0, mktyperef(mkirtype(fn->retty)));
+ efmt(" ");
+ }
for (i = 0; i < 2; ++i) {
if (!blk->jmp.arg[i].t) break;
if (i > 0) efmt(", ");
diff --git a/op.def b/op.def
index 42b7c3c..6ff6882 100644
--- a/op.def
+++ b/op.def
@@ -65,6 +65,7 @@ _(store8, 2)
_(param, 2)
_(arg, 2)
_(call, 2)
+_(call2r, 1)
_(intrin, 2)
_(phi, 1)
/* machine-specific instructions */
diff --git a/regalloc.c b/regalloc.c
index 1b3b765..b3dc694 100644
--- a/regalloc.c
+++ b/regalloc.c
@@ -320,7 +320,7 @@ regalloc(struct function *fn)
spill(&ra, r, blk, i);
}
for (int j = 0; j < call->narg; ++j) {
- short reg = call->abiargregs[j];
+ short reg = call->abiarg[j].reg;
if (reg >= 0) {
forcetake(&ra, reg, mkref(RREG, reg), blk, i);
}