aboutsummaryrefslogtreecommitdiff
path: root/src/asm.cff
blob: a92e14df8e7c4dddc8537c4a4a198b92e3a5ca32 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
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,
};