aboutsummaryrefslogtreecommitdiff
path: root/src/irgen.cff
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-20 11:06:38 +0200
committerlemon <lsof@mailbox.org>2022-08-20 11:06:38 +0200
commit46e1f128fd310bd29a2b4335b36c60d6cc0aa3a7 (patch)
treefeb93a69cf93773d0542435ae09c76de04e509c8 /src/irgen.cff
parentdf41a4512932f1312e4725d0409757a683b091ed (diff)
initial work on IR
Diffstat (limited to 'src/irgen.cff')
-rw-r--r--src/irgen.cff124
1 files changed, 124 insertions, 0 deletions
diff --git a/src/irgen.cff b/src/irgen.cff
new file mode 100644
index 0000000..1ba080d
--- /dev/null
+++ b/src/irgen.cff
@@ -0,0 +1,124 @@
+import "ir.hff";
+import "common.hff";
+
+extern fn ir_genstatic(IR *IRCtx, decl *Decl) void {
+}
+
+struct InstStream {
+ IR *IRCtx,
+ head *IRInst,
+ tail *IRInst,
+ fn push(S *InstStream, inst *IRInst) void {
+ if S.tail {
+ S.tail.next = inst;
+ } else {
+ S.head = inst;
+ }
+ S.tail = inst;
+ }
+}
+
+
+fn mkinstr(S *InstStream, t IRInstT, args [#]IRArg) *IRInst {
+ let inst *IRInst = S.IR.alloc->alloc(sizeof IRInst + (args.#len * sizeof IRArg), alignof IRInst);
+ *inst = { .t: t };
+ for let i = 0; i < args.#len; ++i {
+ inst.args[i] = args[i];
+ }
+ return inst;
+}
+
+defmacro mkslice(Ty, ...args) [ (as([]Ty){args})[0::] ]
+
+fn genblock(S *InstStream, block [#]Stmt) void;
+fn genexpr(S *InstStream, ex *Expr) IRValue {
+ static tmpid int = 0;
+
+ // fold(ex);
+
+ defmacro genunop(u,t) [ {
+ let child = genexpr(S, (u).ex);
+ let res = IRValue{ex.ty, .u: :Tmp(tmpid++)};
+ S->push(mkinstr(S, (t), mkslice(IRArg, :Val(res), :Val(child))));
+ return res;
+ } ]
+
+ defmacro genbinop(b,t) [ {
+ let lhs = genexpr(S, (b).lhs);
+ let rhs = genexpr(S, (b).rhs);
+ let res = IRValue{ex.ty, .u: :Tmp(tmpid++)};
+ S->push(mkinstr(S, (t), mkslice(IRArg, :Val(res), :Val(lhs), :Val(rhs))));
+ return res;
+ } ]
+
+ switch ex.u {
+ case IntLit i; return {ex.ty, :IImm(i.i)};
+ case FloLit f; return {ex.ty, :FImm(f)};
+ case StrLit s; return {ex.ty, :SImm(s)};
+ case BoolLit b; return {ex.ty, :BImm(b)};
+ case NullLit; return {ex.ty, :Null};
+ case UnOp u;
+ switch u.op {
+ case :neg; genunop(u, ex.ty->is(:Int) ? :neg : :fneg);
+ case :compl; genunop(u, :compl);
+ }
+ case BinOp b;
+ switch b.op {
+ case '+'; genbinop(b, ex.ty->is(:Int) ? :add : :fadd);
+ case '-'; genbinop(b, ex.ty->is(:Int) ? :sub : :fsub);
+ case '*'; genbinop(b, ex.ty->is(:Int) ? :mul : :fmul);
+ case '/'; genbinop(b, ex.ty->is(:Int) ? :div : :fdiv);
+ case '%'; genbinop(b, :mod);
+ case '&'; genbinop(b, :band);
+ case '|'; genbinop(b, :bor);
+ case '^'; genbinop(b, :xor);
+ case '<<'; genbinop(b, :lsl);
+ case '>>'; genbinop(b, ex.ty.u.Int.sgn ? :asr : :lsr);
+ }
+ case Call c;
+ let n = c.args.#len;
+ let args [#]IRArg = (as(*IRArg)malloc((n + 2) * sizeof IRArg))[0::n + 2];
+ defer free(args.#ptr);
+ let res = IRValue{ex.ty, .u: :Tmp(tmpid++)};
+ args[0] = :Val(res);
+ if c.lhs.u.#tag == :Symbol {
+ args[1] = :Fn(c.lhs.u.Symbol);
+ for let i = 0; i < n; ++i {
+ args[i + 2] = :Val(genexpr(S, &c.args[i]));
+ }
+ let inst = mkinstr(S, :call, args);
+ inst.call_nargs = n;
+ S->push(inst);
+ return res;
+ } else {
+ }
+
+ }
+ assert(#f, "NYI ex");
+}
+
+fn genstmt(S *InstStream, stmt *Stmt) void {
+ switch stmt.u {
+ case Expr *ex;
+ genexpr(S, ex);
+ case else
+ assert(#f, "NYI st");
+ }
+}
+
+fn genblock(S *InstStream, block [#]Stmt) void {
+ foreach_ptr(st, _, block) {
+ genstmt(S, st);
+ }
+}
+
+extern fn ir_genfn(IR *IRCtx, f *Fn) void {
+ let stream InstStream = {.IR: IR};
+
+ genblock(&stream, f.body.Some);
+ stream->push(mkinstr(&stream, :ret0, {}));
+
+ efmt("----------------------\n");
+ efmt("function %s.%d:\n", container_of(f, Decl, u.Fn).name, f.id);
+ irdump(stream.head);
+}