aboutsummaryrefslogtreecommitdiff
path: root/src/asm.cff
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-21 06:57:48 +0200
committerlemon <lsof@mailbox.org>2022-08-21 06:57:48 +0200
commit135e66c64adf0ef5d2723c243d2f2f6a059ae753 (patch)
tree7fa932722f75534c8492dd776096fc71a1412edc /src/asm.cff
parentfa8aaba64d206330959470e1ffbf0ad0c974456a (diff)
asm prelude, more IR
Diffstat (limited to 'src/asm.cff')
-rw-r--r--src/asm.cff109
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,
+};