diff options
| author | 2025-12-23 11:36:51 +0100 | |
|---|---|---|
| committer | 2025-12-23 11:39:45 +0100 | |
| commit | 7036e19098c295a075f97cbd056fdc43bd490fb2 (patch) | |
| tree | 8e03e29ab8f5645b0b7c71c7663e608b17de0573 | |
| parent | 56cf12a2aca36fabf3c3918947a88cbc4a605bb2 (diff) | |
lower alloca as a separate pass before isel
| -rw-r--r-- | Makefile | 5 | ||||
| -rw-r--r-- | common.h | 1 | ||||
| -rw-r--r-- | ir/dump.c | 3 | ||||
| -rw-r--r-- | ir/ir.c | 2 | ||||
| -rw-r--r-- | ir/ir.h | 4 | ||||
| -rw-r--r-- | ir/stack.c | 37 | ||||
| -rw-r--r-- | main.c | 3 | ||||
| -rw-r--r-- | x86_64/isel.c | 37 | ||||
| -rw-r--r-- | x86_64/sysv.c | 9 |
9 files changed, 65 insertions, 36 deletions
@@ -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)) @@ -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 */ @@ -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"); } } @@ -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); @@ -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: */ @@ -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 */ |