diff options
| author | 2022-08-21 06:57:48 +0200 | |
|---|---|---|
| committer | 2022-08-21 06:57:48 +0200 | |
| commit | 135e66c64adf0ef5d2723c243d2f2f6a059ae753 (patch) | |
| tree | 7fa932722f75534c8492dd776096fc71a1412edc /src/asm.cff | |
| parent | fa8aaba64d206330959470e1ffbf0ad0c974456a (diff) | |
asm prelude, more IR
Diffstat (limited to 'src/asm.cff')
| -rw-r--r-- | src/asm.cff | 109 |
1 files changed, 109 insertions, 0 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, +}; |