aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2025-12-23 11:36:51 +0100
committerlemon <lsof@mailbox.org>2025-12-23 11:39:45 +0100
commit7036e19098c295a075f97cbd056fdc43bd490fb2 (patch)
tree8e03e29ab8f5645b0b7c71c7663e608b17de0573
parent56cf12a2aca36fabf3c3918947a88cbc4a605bb2 (diff)
lower alloca as a separate pass before isel
-rw-r--r--Makefile5
-rw-r--r--common.h1
-rw-r--r--ir/dump.c3
-rw-r--r--ir/ir.c2
-rw-r--r--ir/ir.h4
-rw-r--r--ir/stack.c37
-rw-r--r--main.c3
-rw-r--r--x86_64/isel.c37
-rw-r--r--x86_64/sysv.c9
9 files changed, 65 insertions, 36 deletions
diff --git a/Makefile b/Makefile
index 90cdeef..9818c08 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,7 @@
SRC=main.c io.c mem.c c/c.c c/lex.c c/eval.c c/builtin.c type.c targ.c \
- ir/ir.c ir/builder.c ir/fold.c ir/dump.c ir/ssa.c ir/cfg.c ir/intrin.c ir/abi0.c ir/mem2reg.c ir/regalloc.c ir/simpl.c \
- x86_64/sysv.c x86_64/isel.c x86_64/emit.c obj/obj.c obj/elf.c \
+ ir/ir.c ir/builder.c ir/fold.c ir/dump.c ir/ssa.c ir/cfg.c ir/intrin.c ir/abi0.c ir/mem2reg.c ir/regalloc.c ir/simpl.c ir/stack.c \
+ x86_64/sysv.c x86_64/isel.c x86_64/emit.c \
+ obj/obj.c obj/elf.c \
embedfilesdir.c
CFLAGS=-Wall -std=c11 -pedantic
OBJ=$(patsubst %.c,build/%.o,$(SRC))
diff --git a/common.h b/common.h
index 9e32ded..9804447 100644
--- a/common.h
+++ b/common.h
@@ -143,6 +143,7 @@ struct option {
a : 1, /* after abi0 */
m : 1, /* after mem */
o : 1, /* after optimizations */
+ s : 1, /* after stack */
i : 1, /* after isel */
l : 1, /* after liveness fixup */
r : 1; /* after regalloc */
diff --git a/ir/dump.c b/ir/dump.c
index a2faf27..f952292 100644
--- a/ir/dump.c
+++ b/ir/dump.c
@@ -155,6 +155,9 @@ dumpref(enum op o, union ref ref)
bfmt(out, "]");
}
break;
+ case RSTACK:
+ bfmt(out, "[stack %d]", ref.i);
+ break;
default: assert(!"ref");
}
}
diff --git a/ir/ir.c b/ir/ir.c
index 3c76cde..6edc429 100644
--- a/ir/ir.c
+++ b/ir/ir.c
@@ -650,6 +650,8 @@ irfini(struct function *fn)
simpl(fn);
freearena(fn->passarena);
}
+ lowerstack(fn);
+ freearena(fn->passarena);
if (ccopt.dbg.o) {
bfmt(ccopt.dbgout, "<< Before isel >>\n");
irdump(fn);
diff --git a/ir/ir.h b/ir/ir.h
index dccca0c..4248016 100644
--- a/ir/ir.h
+++ b/ir/ir.h
@@ -62,6 +62,7 @@ enum refkind {
RXCON, /* other constants (incl. external symbols) */
RADDR, /* target-specific addressing mode */
RTYPE, /* irtype */
+ RSTACK, /* stack base offset */
};
union ref {
@@ -325,6 +326,9 @@ void mem2reg(struct function *);
/** intrin.c **/
void lowerintrin(struct function *);
+/** stack.c **/
+void lowerstack(struct function *);
+
/** regalloc.c **/
void regalloc(struct function *);
diff --git a/ir/stack.c b/ir/stack.c
new file mode 100644
index 0000000..2420fdb
--- /dev/null
+++ b/ir/stack.c
@@ -0,0 +1,37 @@
+#include "ir.h"
+
+void
+lowerstack(struct function *fn)
+{
+ extern int ninstr;
+ fn->stksiz = 0;
+ FREQUIRE(FNUSE);
+
+ struct block *blk = fn->entry;
+ do {
+ for (int i = 0; i < blk->ins.n; ++i) {
+ uint alignlog2, siz;
+ int t = blk->ins.p[i];
+ struct instr *ins = &instrtab[t];
+ switch (ins->op) {
+ case Oalloca1: case Oalloca2: case Oalloca4: case Oalloca8: case Oalloca16:
+ alignlog2 = ins->op - Oalloca1;
+ assert(ins->l.i > 0);
+ siz = ins->l.i << alignlog2;
+ fn->stksiz += siz;
+ fn->stksiz = alignup(fn->stksiz, 1 << alignlog2);
+ if (fn->stksiz > (1<<16)-1) error(NULL, "'%s' stack frame too big", fn->name);
+ *ins = mkinstr(Onop,0,);
+ replcuses(mkref(RTMP, t), mkref(RSTACK, fn->stksiz));
+ continue;
+ }
+ }
+ } while ((blk = blk->lnext) != fn->entry);
+
+ if (ccopt.dbg.s) {
+ bfmt(ccopt.dbgout, "<< After stack >>\n");
+ irdump(fn);
+ }
+}
+
+/* vim:set ts=3 sw=3 expandtab: */
diff --git a/main.c b/main.c
index 5a430b4..20f0a17 100644
--- a/main.c
+++ b/main.c
@@ -146,6 +146,7 @@ optparse(char **args)
case 'a': ccopt.dbg.a = 1; break;
case 'm': ccopt.dbg.m = 1; break;
case 'o': ccopt.dbg.o = 1; break;
+ case 's': ccopt.dbg.s = 1; break;
case 'i': ccopt.dbg.i = 1; break;
case 'l': ccopt.dbg.l = 1; break;
case 'r': ccopt.dbg.r = 1; break;
@@ -578,7 +579,7 @@ prihelp(void)
" -help \tPrint this help message\n"
" -std=<..> \tSet C standard (c89, c99, c11, c23)\n"
" -pedantic \tWarnings for strict standards compliance\n"
- " -d{pamoilr} \tDebug print IR after {parse, abi, mem, opts, isel, live, rega}\n"
+ " -d{pamosilr} \tDebug print IR after {parse, abi, mem, opts, stack, isel, live, rega}\n"
" -o <file> \tPlace the output into <file>\n"
" -v \tVerbose output\n"
" -c \tEmit object file but do not link\n"
diff --git a/x86_64/isel.c b/x86_64/isel.c
index 0392386..2b83093 100644
--- a/x86_64/isel.c
+++ b/x86_64/isel.c
@@ -47,12 +47,6 @@ picfixsym(union ref *r, struct block *blk, int *curi)
*r = insertinstr(blk, (*curi)++, mkinstr(Ocopy, KPTR, .l = *r));
}
-/* map alloca tmp -> stack frame displacement (0 if not alloca) */
-static ushort *stkslots;
-static uint nstkslots;
-
-#define isstkslot(r) ((r).t == RTMP && (r).i < nstkslots && stkslots[(r).i])
-
static void
fixarg(union ref *r, struct instr *ins, struct block *blk, int *curi)
{
@@ -107,8 +101,8 @@ fixarg(union ref *r, struct instr *ins, struct block *blk, int *curi)
sh = r->i;
ShiftImm: /* shift immediate is always 8bit */
*r = mkref(RICON, sh & 255);
- } else if (isstkslot(*r)) {
- struct instr adr = mkinstr(Oadd, KPTR, mkref(RREG, RBP), mkintcon(KI32, -stkslots[r->i]));
+ } else if (r->t == RSTACK) {
+ struct instr adr = mkinstr(Oadd, KPTR, mkref(RREG, RBP), mkintcon(KI32, -r->i));
if (op == Ocopy)
*ins = adr;
else
@@ -246,8 +240,8 @@ ascale(struct addr *addr, union ref a, union ref b)
static bool
aadd(struct addr *addr, struct block *blk, int *curi, union ref r)
{
- if (isstkslot(r)) {
- if (addr->base.bits || !aimm(addr, -stkslots[r.i])) goto Ref;
+ if (r.t == RSTACK) {
+ if (addr->base.bits || !aimm(addr, -r.i)) goto Ref;
addr->base = mkref(RREG, RBP);
} else if (r.t == RTMP) {
struct instr *ins = &instrtab[r.i];
@@ -283,8 +277,8 @@ aadd(struct addr *addr, struct block *blk, int *curi, union ref r)
* safely hoisted into an address value, unless they have global lifetime */
if (!rstest(mctarg->rglob, r.i)) return 0;
Ref:
- if (isstkslot(r) && (addr->base.bits || addr->index.bits)) {
- r = insertinstr(blk, (*curi)++, mkinstr(Oadd, KPTR, mkref(RREG, RBP), mkref(RICON, -stkslots[r.i])));
+ if (r.t == RSTACK && (addr->base.bits || addr->index.bits)) {
+ r = insertinstr(blk, (*curi)++, mkinstr(Oadd, KPTR, mkref(RREG, RBP), mkref(RICON, -r.i)));
}
if (!addr->base.bits) addr->base = r;
else if (!addr->index.bits) addr->index = r;
@@ -308,7 +302,7 @@ fuseaddr(union ref *r, struct block *blk, int *curi)
}
return 1;
}
- if (r->t != RTMP) return 0;
+ if (r->t != RSTACK && r->t != RTMP) return 0;
if (!aadd(&addr, blk, curi, *r)) return 0;
if (isaddrcon(addr.base,0) && (ccopt.pic || (ccopt.pie && addr.index.bits) || conht[addr.base.i].isfunc)) {
@@ -337,8 +331,8 @@ addarg4addrp(union ref r)
{
struct instr *ins;
if (r.t == RXCON && !conht[r.i].cls && !conht[r.i].deref) return 1; /* sym or dat ref */
+ if (r.t == RSTACK) return 1;
if (r.t != RTMP) return 0;
- if (isstkslot(r)) return 1;
ins = &instrtab[r.i];
return ins->op == Oshl || (ins->op == Ocopy && ins->l.t == RADDR) || ins->op == Oadd;
}
@@ -350,7 +344,7 @@ loadstoreaddr(struct block *blk, union ref *r, int *curi)
*r = mkaddr((struct addr){.base = *r});
} else if (isaddrcon(*r, 0)) {
picfixsym(r, blk, curi);
- } else if (r->t == RTMP) {
+ } else if (r->t == RTMP || r->t == RSTACK) {
if (addarg4addrp(*r)) fuseaddr(r, blk, curi);
} else if (r->t != RREG) {
*r = insertinstr(blk, (*curi)++, mkinstr(Ocopy, KPTR, *r));
@@ -373,7 +367,6 @@ arithfold(struct instr *ins)
static void
sel(struct function *fn, struct instr *ins, struct block *blk, int *curi)
{
- uint siz, alignlog2;
int t = ins - instrtab;
struct instr temp = {0};
enum op op = ins->op;
@@ -387,14 +380,7 @@ sel(struct function *fn, struct instr *ins, struct block *blk, int *curi)
default: assert(0);
case Onop: break;
case Oalloca1: case Oalloca2: case Oalloca4: case Oalloca8: case Oalloca16:
- alignlog2 = ins->op - Oalloca1;
- assert(ins->l.i > 0);
- siz = ins->l.i << alignlog2;
- fn->stksiz += siz;
- fn->stksiz = alignup(fn->stksiz, 1 << alignlog2);
- if (fn->stksiz > (1<<16)-1) error(NULL, "'%s' stack frame too big", fn->name);
- stkslots[t] = fn->stksiz;
- *ins = mkinstr(Onop,0,);
+ assert(!"unlowered alloca");
break;
case Oparam:
assert(ins->l.t == RICON && ins->l.i < fn->nabiarg);
@@ -623,11 +609,8 @@ seljmp(struct function *fn, struct block *blk)
void
x86_64_isel(struct function *fn)
{
- extern int ninstr;
struct block *blk = fn->entry;
- fn->stksiz = 0;
- stkslots = allocz(fn->passarena, (nstkslots = ninstr) * sizeof *stkslots, 0);
do {
int i;
for (i = 0; i < blk->phi.n; ++i) {
diff --git a/x86_64/sysv.c b/x86_64/sysv.c
index 1c63782..6313b07 100644
--- a/x86_64/sysv.c
+++ b/x86_64/sysv.c
@@ -70,7 +70,6 @@ abiarg(short r[2], uchar cls[2], uchar *r2off, int *ni, int *nf, int *ns, union
{
static const uchar intregs[] = { RDI, RSI, RDX, RCX, R8, R9 };
enum { NINT = countof(intregs), NFLT = 8 };
- int ret, ni_save, nf_save;
if (!typ.isagg) {
if (kisflt(cls[0] = typ.cls) && *nf < NFLT) {
@@ -85,14 +84,14 @@ abiarg(short r[2], uchar cls[2], uchar *r2off, int *ni, int *nf, int *ns, union
return 1;
}
cls[0] = cls[1] = 0;
- ret = classify(cls, &typedata[typ.dat], 0);
+ int ret = classify(cls, &typedata[typ.dat], 0);
if (!ret) { /*MEMORY*/
r[0] = *ns;
*ns = alignup(*ns + typedata[typ.dat].siz, 8);
return 0;
}
assert(ret <= 2);
- ni_save = *ni, nf_save = *nf;
+ int ni_save = *ni, nf_save = *nf;
*r2off = 8;
for (int i = 0; i < ret; ++i) {
assert(cls[i]);
@@ -114,15 +113,13 @@ abiarg(short r[2], uchar cls[2], uchar *r2off, int *ni, int *nf, int *ns, union
static int
abiret(short r[2], uchar cls[2], uchar *r2off, int *ni, union irtype typ)
{
- int ret;
-
if (!typ.isagg) {
r[0] = kisflt(cls[0] = typ.cls) ? XMM0 : RAX;
return 1;
}
cls[0] = cls[1] = 0;
- ret = classify(cls, &typedata[typ.dat], 0);
+ int ret = classify(cls, &typedata[typ.dat], 0);
if (!ret) { /* MEMORY */
assert(*ni == 0);
r[0] = RAX; /* on return should contain result location address */