diff options
| author | 2022-08-21 06:57:48 +0200 | |
|---|---|---|
| committer | 2022-08-21 06:57:48 +0200 | |
| commit | 135e66c64adf0ef5d2723c243d2f2f6a059ae753 (patch) | |
| tree | 7fa932722f75534c8492dd776096fc71a1412edc /src | |
| parent | fa8aaba64d206330959470e1ffbf0ad0c974456a (diff) | |
asm prelude, more IR
Diffstat (limited to 'src')
| -rw-r--r-- | src/asm.cff | 109 | ||||
| -rw-r--r-- | src/cffc.hff | 15 | ||||
| -rw-r--r-- | src/irdump.cff | 10 | ||||
| -rw-r--r-- | src/irgen.cff | 100 | ||||
| -rw-r--r-- | src/main.cff | 1 | ||||
| -rw-r--r-- | src/parse.cff | 20 | ||||
| -rw-r--r-- | src/targ.cff | 6 |
7 files changed, 225 insertions, 36 deletions
diff --git a/src/asm.cff b/src/asm.cff new file mode 100644 index 0000000..a92e14d --- /dev/null +++ b/src/asm.cff @@ -0,0 +1,109 @@ +import "cffc.hff"; +import "common.hff"; + +struct ASM { + outf *FILE, + lastsection enum { none, data, text }, + + fn gen(A *ASM, fmt *const u8, ...) void { + let ap va_list #?; + ap->start(fmt); + fn fmtproc(c u8, fp *void) void { + fputc(c, fp); + } + for let c = *fmt; c != 0; c = *++fmt { + if c != '%' { + fputc(c, A.outf); + continue; + } + switch (c = *++fmt) { + case 's'; + fprintf(A.outf, "%s", ap->arg(*const u8)); + case 'd'; + fprintf(A.outf, "%d", ap->arg(int)); + case 'I'; + fprintf(A.outf, "%lld", as(c_llong) ap->arg(i64)); + case 'f'; + fprintf(A.outf, "%.17f", ap->arg(f64)); + case 'z'; + fprintf(A.outf, "%llu", as(c_ullong) ap->arg(usize)); + case 'S'; + pfmt(&fmtproc, A.outf, "%S", ap->arg([#]const u8)); + case else + assert(#f, "bad fmt '%c'", c); + } + } + ap->end(); + } +} + +fn init(B *Backend, outf *FILE) void { + B.impl = calloc(1, sizeof ASM); + let impl *ASM = B.impl; + impl.outf = outf; +} + +static directive4size []*const u8 = { + [1] = "byte", + [2] = "short", + [4] = "int", + [8] = "quad" +}; + +fn gendata(A *ASM, ty *const Type, ex *Expr) void { + switch ex.u { + case ZeroIni; + A->gen(".fill %z", ty.size); + case IntLit i; + A->gen(".%s %I", directive4size[ty.size], i.i); + case FloLit f; + A->gen(".%s %f", ty.size == 4 ? "single" : "double", f); + case StrLit s; + if ty->is(:Arr) { + A->gen(".ascii %S", s); + } else { + static id int = 0; + A->gen(".%s strlit%d.", directive4size[g_targ.ptrsize], id); + A->gen("\nstrlit%d.:\n\t.ascii %S", id++, s); + } + case else + assert(#f, "NYI data"); + } +} + +fn genstatic(A *ASM, decl *Decl) void { + if decl.u.Static.fwd { + return; + } + if A.lastsection != :data { + A->gen(".section data\n"); + A.lastsection = :data; + } + if decl.externp { + A->gen(".globl %s\n%s:\n", decl.name, decl.name); + } else { + A->gen("%s.s%d:\n", decl.name, decl.u.Static.id); + } + A->gen("\t.align %z\n", decl.u.Static.ty.align); + switch decl.u.Static.ini { + case None; + A->gen("\t.fill %z\n", decl.u.Static.ty.size); + case Some *ex; + A->gen("\t"); + gendata(A, decl.u.Static.ty, ex); + A->gen("\n"); + } +} + +fn bgenstatic(B *Backend, decl *Decl) void { + genstatic(B.impl, decl); +} + +fn bgenfn(B *Backend, Fn *Fn) void { +} + +extern static g_asmbackend Backend = { + .initf: &init, + .genstaticf: &bgenstatic, + .genfnf: &bgenfn, +}; diff --git a/src/cffc.hff b/src/cffc.hff index 31af5fb..c8e3f11 100644 --- a/src/cffc.hff +++ b/src/cffc.hff @@ -321,6 +321,14 @@ struct DeclList { decl Decl, } + +struct Backend { + impl *void, + initf *fn(*Backend, *FILE) void, + genstaticf *fn(*Backend, *Decl) void, + genfnf *fn(*Backend, *Fn) void, +} + struct Targ { name *const u8, ptrsize u8, @@ -333,6 +341,8 @@ struct Targ { valistsize u8, valistalign u8, charsigned bool, shortenum bool, + + B *Backend, } // parse.cff @@ -351,7 +361,7 @@ extern fn err(P *Parser, Loc, fmt *const u8, ...) void; extern fn fatal(*Parser, Loc, fmt *const u8, ...) void; // targ.cff -extern static g_targ *const Targ; +extern static g_targ Targ; extern fn targ_ini(name *const u8) bool; // type.cff @@ -443,3 +453,6 @@ extern fn mkirctx(*Allocator) *IRCtx; extern fn ir_genstatic(*IRCtx, *Decl) void; extern fn ir_genfn(*IRCtx, *Fn) void; extern fn ir_free(*IRCtx) void; + +// asm.cff +extern static g_asmbackend Backend; diff --git a/src/irdump.cff b/src/irdump.cff index 0942f87..ee68f91 100644 --- a/src/irdump.cff +++ b/src/irdump.cff @@ -144,8 +144,14 @@ extern fn irdump(inst *IRInst) void { dump("set %a, %a\n", inst.args[0], inst.args[1]); continue #'dump; } - exprinst(:load, "load", 2) - stmtinst(:store, "store", 2) + if inst.t == :load { + dump("%a(%t) = load %a[%a]\n", inst.args[0], inst.args[0].Val.ty, inst.args[1], inst.args[2]); + continue #'dump; + } + if inst.t == :store { + dump("store %a[%a], %a\n", inst.args[0], inst.args[1], inst.args[2]); + continue #'dump; + } stmtinst(:ret0, "ret", 0); stmtinst(:ret, "ret", 1); if inst.t == :beqz { diff --git a/src/irgen.cff b/src/irgen.cff index 1cd5172..9d32bfd 100644 --- a/src/irgen.cff +++ b/src/irgen.cff @@ -3,6 +3,7 @@ import "common.hff"; import "map.hff"; extern fn ir_genstatic(IR *IRCtx, decl *Decl) void { + g_targ.B.genstaticf(g_targ.B, decl); } struct IntTraits { @@ -64,7 +65,7 @@ fn genblock(S *InstStream, block [#]Stmt) void; fn genexpr(S *InstStream, ex *Expr) IRValue { static tmpid int = 0; - // fold(ex); + fold(ex); defmacro genunop(u,t) [ { let child = genexpr(S, (u).ex); @@ -94,7 +95,12 @@ fn genexpr(S *InstStream, ex *Expr) IRValue { case :neg; genunop(u, ex.ty->is(:Int) ? :neg : :fneg); case :not; genunop(u, :not); case :compl; genunop(u, :compl); - case :deref; genunop(u, :load); + case :deref; + let child = genexpr(S, (u).ex); + let res = IRValue{ex.ty, .u: :Tmp(tmpid++)}; + let inst = S->mkinst3({:load}, :Val(res), :Val(child), :Val{ty_int,:IImm(0)}); + S->push(inst); + return res; case :preinc, :predec; let one = u.op == :preinc ? 1 : -1; switch u.ex.u { @@ -106,14 +112,8 @@ fn genexpr(S *InstStream, ex *Expr) IRValue { S->push(rhs); let inst = S->mkinst2({:setvar}, :Val(ex), :Val(inced)); S->push(inst); - let ex = genexpr(S, u.ex); - if decl.u.#tag == :Let { - return {ex.ty, :Local(decl)}; - } else { - return {ex.ty, :Global(decl)}; - } + return inced; } - } case BinOp b; switch b.op { @@ -146,27 +146,58 @@ fn genexpr(S *InstStream, ex *Expr) IRValue { S->push(inst); return res; case '='; - switch b.lhs.u { + switch b.lhs.u { // var = ex case Symbol decl; - let inst = S->mkinst2({:setvar}, :Val(genexpr(S, b.lhs)), :Val(genexpr(S, b.rhs))); + let r = genexpr(S, b.rhs); + let inst = S->mkinst2({:setvar}, :Val(genexpr(S, b.lhs)), :Val(r)); S->push(inst); - if decl.u.#tag == :Let { - return {ex.ty, :Local(decl)}; - } else { - return {ex.ty, :Global(decl)}; - } - case UnOp u; + return r; + case UnOp u; // *a = ex assert(u.op == :deref, "deref?? unop="); let child = genexpr(S, u.ex); - let inst = S->mkinst2({:store}, :Val(child), :Val(genexpr(S, b.rhs))); + let r = genexpr(S, b.rhs); + let inst = S->mkinst3({:store}, :Val(child), :Val{ty_int,:IImm(0)}, :Val(r)); S->push(inst); - let it = genexpr(S, b.lhs); - return it; - + return r; + case Index index; // a[b] = ex + let indexee = genexpr(S, index.lhs); + let index = genexpr(S, index.rhs); + let newval = genexpr(S, b.rhs); + S->push(S->mkinst3({:store}, :Val(indexee), :Val(index), :Val(newval))); + return newval; case else assert(#f, "nyi ="); } + case '+=', '-=', '*=', '/=', '%=', '&=', '|=', '^=', '<<=', '>>='; + let o IRInstT = b.op == '+=' ? (ex.ty->is(:Flo) ? :fadd : :add) + : b.op == '-=' ? (ex.ty->is(:Flo) ? :fsub : :sub) + : b.op == '*=' ? (ex.ty->is(:Flo) ? :fmul : :mul) + : b.op == '/=' ? (ex.ty->is(:Flo) ? :fdiv : :div) + : b.op == '%=' ? :mod + : b.op == '&=' ? :band + : b.op == '|=' ? :bor + : b.op == '<<=' ? :lsl + : b.op == '>>=' ? (ex.ty.u.Int.sgn ? :asr : :lsr) : :nop; + switch b.lhs.u { + case Symbol decl; // var += ex + let lhs = genexpr(S, b.lhs); + let rhs = genexpr(S, b.rhs); + let new = IRValue{ex.ty, .u: :Tmp(tmpid++)}; + S->push(S->mkinst3({o}, :Val(new), :Val(lhs), :Val(rhs))); + let inst = S->mkinst2({:setvar}, :Val(lhs), :Val(new)); + S->push(inst); + return new; + } + } + case Index idx; + let i = genexpr(S, idx.lhs); + let off = genexpr(S, idx.rhs); + let res = IRValue{ex.ty, .u: :Tmp(tmpid++)}; + let inst = S->mkinst3({:load}, :Val(res), :Val(i), :Val(off)); + S->push(inst); + return res; + case Cond c; let test = genexpr(S, c.test); let beqz = S->mkinst1({:beqz}, :Val(test)); @@ -226,6 +257,15 @@ fn genstmt(S *InstStream, stmt *Stmt) void { } case If If; + #{ + %t = <test> + beqz %t, .L0 + <t> + b .L1 + .L0: + <f> + .L1: + } let t = genexpr(S, &If.test); let beqz = S->mkinst1({:beqz}, :Val(t)); S->push(beqz); @@ -241,6 +281,14 @@ fn genstmt(S *InstStream, stmt *Stmt) void { } case While loop; + #{ + .cont: + %t = <test> + beqz %t, .brk + <body> + b .cont + .brk: + } let begin = S->pushnop(); let t = genexpr(S, &loop.test); let beqz = S->mkinst1({:beqz}, :Val(t)); @@ -277,12 +325,14 @@ fn genstmt(S *InstStream, stmt *Stmt) void { beqz.branch = end; case Break id; - let jumpto = *S.loopbrks->get(id); - S->push(S->mkinst({:b, .branch: jumpto},0)); + let jumpto = S.loopbrks->get(id); + assert(jumpto != #null, "no brk label %d", id); + S->push(S->mkinst({:b, .branch: *jumpto},0)); case Continue id; - let jumpto = *S.loopconts->get(id); - S->push(S->mkinst({:b, .branch: jumpto},0)); + let jumpto = S.loopconts->get(id); + assert(jumpto != #null, "no cont label %d", id); + S->push(S->mkinst({:b, .branch: *jumpto},0)); case Return retex; if retex->empty() { diff --git a/src/main.cff b/src/main.cff index 5246c60..ac4ca70 100644 --- a/src/main.cff +++ b/src/main.cff @@ -5,7 +5,6 @@ extern fn main(argc int, argv **u8) int { assert(argc > 1, "args?"); targ_ini("amd64-sysv"); - assert(g_targ != #null, "target?"); let p = Parser {}; parser_init(&p, argv[1]); diff --git a/src/parse.cff b/src/parse.cff index 43c4e7d..11c17cc 100644 --- a/src/parse.cff +++ b/src/parse.cff @@ -2092,17 +2092,18 @@ fn pstfor(P *Parser, loc Loc, label *const u8) Stmt { lexexpect(P, '{'); } let body [#]Stmt #?; - with_tmpchange(P.curloop, ++P.loopid) { + let id = ++P.loopid; + with_tmpchange(P.curloop, id) { let env = mkenv(P.curenv, P.alloc); defer envfree(env); pushenv(P, env); if label { - putdecl(P, loc, { label, loc, .u: :Label(P.loopid) }); + putdecl(P, loc, { label, loc, .u: :Label(id) }); } body = parseblock(P); popenv(P); } - return { loc, :For { ini, test, next, body, P.loopid }}; + return { loc, :For { ini, test, next, body, id }}; } fn pstiswitch(P *Parser, loc Loc, ex Expr) Stmt { @@ -2396,8 +2397,12 @@ fn parsevardecl(P *Parser, toplevel bool, externp bool, letp bool, yield DeclYie ty = constify(ty); } - let decl Decl = { name, tok.loc, externp, :Let { ty, ini, fwd, P.curfn ? P.curfn.id : 0, P.varid++ } }; - if !letp { + let decl Decl = { name, tok.loc, externp, :Let { ty, ini, fwd, P.curfn ? P.curfn.id : 0, } }; + if letp { + decl.u.Let.id = P.varid++; + } else { + static id int = 0; + decl.u.Static.id = id++; decl.u.#tag = :Static; } yield(putdecl(P, tok.loc, decl), yarg); @@ -2436,6 +2441,9 @@ fn parsefn(P *Parser, loc Loc, externp bool, name *const u8) *Decl { return decl; } + let varid = P.varid, loopid = P.loopid; + P.varid = 0; + P.loopid = 0; with_tmpchange(P.alloc, &Allocator { &Arena {}, &Arena:allocf }) { with_tmpchange(P.curfn, Fn) { let env = mkenv(P.curenv, P.alloc); @@ -2454,6 +2462,8 @@ fn parsefn(P *Parser, loc Loc, externp bool, name *const u8) *Decl { (as(*Arena)P.alloc.a)->destroy(); } } + P.varid = varid; + P.loopid = loopid; return decl; } diff --git a/src/targ.cff b/src/targ.cff index 895a20a..38fcb48 100644 --- a/src/targ.cff +++ b/src/targ.cff @@ -17,12 +17,14 @@ static const targs []const Targ = { } }; -extern static g_targ *const Targ = {}; +extern static g_targ Targ = {}; extern fn targ_ini(name *const u8) bool { foreach(targ, i, targs[0::]) { if streq(name, targ.name) { - g_targ = &targs[i]; + g_targ = targs[i]; + g_targ.B = &g_asmbackend; + g_targ.B.initf(g_targ.B, stdout); return #t; } } |