aboutsummaryrefslogtreecommitdiffhomepage
path: root/ir
diff options
context:
space:
mode:
Diffstat (limited to 'ir')
-rw-r--r--ir/abi0.c16
-rw-r--r--ir/builder.c8
-rw-r--r--ir/dump.c4
-rw-r--r--ir/ir.c53
-rw-r--r--ir/ir.h9
-rw-r--r--ir/op.def3
6 files changed, 68 insertions, 25 deletions
diff --git a/ir/abi0.c b/ir/abi0.c
index 404947e..dc479bf 100644
--- a/ir/abi0.c
+++ b/ir/abi0.c
@@ -32,6 +32,7 @@ abiret(struct abiarg abiret[2], struct abiargsvec *abiargs, int *ni, union irtyp
}
for (int i = 0; i < retreg; ++i) {
abiret[i].ty = cls2type(cls[i]);
+ abiret[i].isstk = 0;
abiret[i].reg = r[i];
}
return retreg;
@@ -44,7 +45,7 @@ abiarg(struct abiargsvec *abiargs, int *ni, int *nf, int *ns, union irtype ty)
uchar cls[2];
int ret = mctarg->abiarg(r, cls, ni, nf, ns, ty);
if (!ret) { /* in stack */
- vpush(abiargs, ((struct abiarg) { ty, .stk = r[0] }));
+ vpush(abiargs, ((struct abiarg) { ty, .isstk = 1, .stk = r[0] }));
} else if (ret == 1 && ty.isagg && cls[0] == KPTR) { /* aggregate by pointer */
vpush(abiargs, ((struct abiarg) { cls2type(cls[0]), .reg = r[0] }));
} else { /* by regs */
@@ -59,7 +60,7 @@ static struct instr
copyparam(struct function *fn, int *curi, int param, struct abiarg abi)
{
struct instr par = mkinstr(Oparam, abi.ty.cls, mkref(RICON, param), mktyperef(abi.ty));
- if (abi.reg >= 0) { /* reg */
+ if (!abi.isstk) { /* reg */
assert(!abi.ty.isagg);
return par;
} else if (!abi.ty.isagg) { /* scalar in stack */
@@ -237,7 +238,6 @@ abi0_call(struct function *fn, struct instr *ins, struct block *blk, int *curi)
struct call *call = &calltab.p[ins->r.i];
vararg = call->vararg;
- vinit(&abiargs, abiargsbuf, arraylength(abiargsbuf));
ni = nf = ns = 0;
assert(!ins->cls == !call->ret.bits);
nret = abiret(call->abiret, &abiargs, &ni, call->ret);
@@ -282,7 +282,7 @@ abi0_call(struct function *fn, struct instr *ins, struct block *blk, int *curi)
ins->cls = 0;
if (!nret) { /* hidden pointer argument */
ins->cls = 0;
- if (call->abiret[0].reg >= 0) {
+ if (!call->abiret[0].isstk) {
/* the result location pointer is also returned by the callee, e.g. in x86 */
ins->cls = KPTR;
++nret;
@@ -401,11 +401,12 @@ abi0(struct function *fn)
blk = fn->entry->lnext;
do {
- /* adjust calls */
+ /* adjust vaargs and calls */
for (int iinstr = 0; iinstr < blk->ins.n; ++iinstr) {
struct instr *ins = &instrtab[blk->ins.p[iinstr]];
- if (ins->op != Ocall) continue;
- abi0_call(fn, ins, blk, &iinstr);
+ if (ins->op == Ovastart) mctarg->vastart(fn, blk, &iinstr);
+ else if (ins->op == Ovaarg) mctarg->vaarg(fn, blk, &iinstr);
+ else if (ins->op == Ocall) abi0_call(fn, ins, blk, &iinstr);
}
/* adjust returns */
@@ -432,6 +433,7 @@ abi0(struct function *fn)
}
} while ((blk = blk->lnext) != fn->entry);
+ sortrpo(fn);
if (ccopt.dbg.a) {
efmt("<< After abi0 >>\n");
irdump(fn);
diff --git a/ir/builder.c b/ir/builder.c
index 964099a..640c1fd 100644
--- a/ir/builder.c
+++ b/ir/builder.c
@@ -124,12 +124,12 @@ irunop(struct function *fn, enum op op, enum irclass k, union ref a)
return addinstr(fn, mkinstr(op, k, a));
}
-int newinstr(void);
+int allocinstr(void);
union ref
addinstr(struct function *fn, struct instr ins)
{
- int new = newinstr();
+ int new = allocinstr();
assert(fn->curblk != NULL);
instrtab[new] = ins;
adduse(fn->curblk, new, ins.l);
@@ -168,8 +168,8 @@ addphi(struct function *fn, enum irclass cls, union ref *r)
ins.l = mkref(RXXX, phitab.n-1);
assert(fn->curblk != NULL);
- assert(fn->curblk->ins.n == 0);
- new = newinstr();
+ /*assert(fn->curblk->ins.n == 0);*/
+ new = allocinstr();
instrtab[new] = ins;
for (int i = 0; i < fn->curblk->npred; ++i) {
adduse(fn->curblk, new, r[i]);
diff --git a/ir/dump.c b/ir/dump.c
index f261150..2245d3f 100644
--- a/ir/dump.c
+++ b/ir/dump.c
@@ -173,7 +173,7 @@ dumpinst(const struct instr *ins)
efmt("\n");
}
-static void
+void
dumpblk(struct function *fn, struct block *blk)
{
static const char *jnames[] = { 0, "b", "ret" };
@@ -228,7 +228,7 @@ irdump(struct function *fn)
efmt("abi: (");
for (int i = 0; i < fn->nabiarg; ++i) {
if (i > 0) efmt(", ");
- if (fn->abiarg[i].reg >= 0) {
+ if (!fn->abiarg[i].isstk) {
efmt("%s", mctarg->rnames[fn->abiarg[i].reg]);
} else {
prityp(fn->abiarg[i].ty);
diff --git a/ir/ir.c b/ir/ir.c
index f3e6e89..0f716f9 100644
--- a/ir/ir.c
+++ b/ir/ir.c
@@ -234,8 +234,7 @@ delpred(struct block *blk, struct block *p)
struct block *
newblk(struct function *fn)
{
- struct block *blk = alloc(fn->arena, sizeof(struct block), 0);
- memset(blk, 0, sizeof *blk);
+ struct block *blk = allocz(fn->arena, sizeof(struct block), 0);
blk->id = -1;
return blk;
}
@@ -297,8 +296,36 @@ insertblk(struct function *fn, struct block *pred, struct block *subst)
assert(0);
}
+struct block *
+blksplitafter(struct function *fn, struct block *blk, int idx)
+{
+ struct block *new = newblk(fn);
+ ++fn->nblk;
+ new->lprev = blk;
+ new->lnext = blk->lnext;
+ blk->lnext = new;
+ new->lnext->lprev = new;
+ if (idx < blk->ins.n-1)
+ vpushn(&new->ins, &blk->ins.p[idx+1], blk->ins.n-idx-1);
+ blk->ins.n -= new->ins.n;
+ new->jmp = blk->jmp;
+ blk->jmp.t = Jb;
+ memset(blk->jmp.arg, 0, sizeof blk->jmp.arg);
+ for (int i = 0; i < 2; ++i) {
+ struct block *s = (&blk->s1)[i];
+ for (int i = 0; i < s->npred; ++i) {
+ if (blkpred(s, i) == blk)
+ blkpred(s, i) = new;
+ }
+ }
+ new->s1 = blk->s1, new->s2 = blk->s2;
+ blk->s1 = new, blk->s2 = NULL;
+ addpred(new, blk);
+ return new;
+}
+
int
-newinstr(void)
+allocinstr(void)
{
int t;
if (instrfreelist != -1) {
@@ -358,12 +385,22 @@ Shrink:
return 1;
}
+int
+newinstr(struct block *at, struct instr ins)
+{
+ int new = allocinstr();
+ instrtab[new] = ins;
+ if (at) {
+ adduse(at, new, ins.l);
+ adduse(at, new, ins.r);
+ }
+ return new;
+}
+
union ref
insertinstr(struct block *blk, int idx, struct instr ins)
{
- int new = newinstr();
-
- instrtab[new] = ins;
+ int new = newinstr(blk, ins);
if (idx == blk->ins.n) vpush(&blk->ins, new);
else {
assert(idx >= 0 && idx < blk->ins.n);
@@ -373,15 +410,13 @@ insertinstr(struct block *blk, int idx, struct instr ins)
blk->ins.p[i] = blk->ins.p[i - 1];
blk->ins.p[idx] = new;
}
- adduse(blk, new, ins.l);
- adduse(blk, new, ins.r);
return mkref(RTMP, new);
}
union ref
insertphi(struct block *blk, enum irclass cls)
{
- int new = newinstr();
+ int new = allocinstr();
union ref *refs = NULL;
assert(blk->npred > 0);
xbgrowz(&refs, blk->npred);
diff --git a/ir/ir.h b/ir/ir.h
index 66fc56d..22b920f 100644
--- a/ir/ir.h
+++ b/ir/ir.h
@@ -37,8 +37,8 @@ struct xcon {
struct abiarg {
union irtype ty;
union {
- short reg; /* >= 0 */
- short stk; /* < 0 */
+ struct { ushort _ : 1, reg : 15; };
+ struct { ushort isstk : 1, stk : 15; };
};
};
@@ -188,7 +188,8 @@ struct mctarg {
* or negative SP offset if stack
*/
int (*abiarg)(short r[2], uchar cls[2], int *ni, int *nf, int *ns, union irtype);
-
+ void (*vastart)(struct function *, struct block *, int *curi);
+ void (*vaarg)(struct function *, struct block *, int *curi);
void (*isel)(struct function *);
void (*emit)(struct function *);
};
@@ -236,7 +237,9 @@ void addpred(struct block *blk, struct block *p);
struct block *newblk(struct function *);
void freeblk(struct function *, struct block *);
struct block *insertblk(struct function *, struct block *pred, struct block *subst);
+struct block *blksplitafter(struct function *, struct block *, int idx);
void adduse(struct block *ublk, int ui, union ref r);
+int newinstr(struct block *at, struct instr ins);
union ref insertinstr(struct block *, int idx, struct instr);
union ref insertphi(struct block *, enum irclass cls);
void replcuses(union ref from, union ref to);
diff --git a/ir/op.def b/ir/op.def
index 0c94d09..7bcaad1 100644
--- a/ir/op.def
+++ b/ir/op.def
@@ -69,6 +69,9 @@ _(call2r, 1)
_(intrin, 2)
_(phi, 1)
_(swap, 2)
+_(vastart, 1)
+_(vaarg, 2)
/* machine-specific instructions */
+_(xvaprologue, 1)
_(xsave, 1)
_(xrestore, 1)