aboutsummaryrefslogtreecommitdiff
path: root/src/irgen.cff
diff options
context:
space:
mode:
Diffstat (limited to 'src/irgen.cff')
-rw-r--r--src/irgen.cff134
1 files changed, 108 insertions, 26 deletions
diff --git a/src/irgen.cff b/src/irgen.cff
index 1ba080d..c0c4a16 100644
--- a/src/irgen.cff
+++ b/src/irgen.cff
@@ -4,6 +4,9 @@ import "common.hff";
extern fn ir_genstatic(IR *IRCtx, decl *Decl) void {
}
+struct InstStream;
+
+
struct InstStream {
IR *IRCtx,
head *IRInst,
@@ -16,19 +19,39 @@ struct InstStream {
}
S.tail = inst;
}
-}
+ fn mkinst(S *InstStream, inst0 IRInst, narg uint) *IRInst {
+ let inst *IRInst = S.IR.alloc->alloc(sizeof IRInst + (narg * sizeof IRArg), alignof IRInst);
+ *inst = inst0;
+ return 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];
+ fn mkinst1(S *InstStream, inst0 IRInst, a IRArg) *IRInst {
+ let inst = S->mkinst(inst0, 1);
+ inst.args[0] = a;
+ return inst;
+ }
+
+ fn mkinst2(S *InstStream, inst0 IRInst, a IRArg, b IRArg) *IRInst {
+ let inst = S->mkinst(inst0, 2);
+ inst.args[0] = a;
+ inst.args[1] = b;
+ return inst;
+ }
+
+ fn mkinst3(S *InstStream, inst0 IRInst, a IRArg, b IRArg, c IRArg) *IRInst {
+ let inst = S->mkinst(inst0, 3);
+ inst.args[0] = a;
+ inst.args[1] = b;
+ inst.args[2] = c;
+ return inst;
+ }
+
+ fn pushnop(S *InstStream) void {
+ S->push(S->mkinst({:nop}, 0));
}
- return inst;
}
-defmacro mkslice(Ty, ...args) [ (as([]Ty){args})[0::] ]
fn genblock(S *InstStream, block [#]Stmt) void;
fn genexpr(S *InstStream, ex *Expr) IRValue {
@@ -39,7 +62,8 @@ fn genexpr(S *InstStream, ex *Expr) IRValue {
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))));
+ let inst = S->mkinst2({t}, :Val(res), :Val(child));
+ S->push(inst);
return res;
} ]
@@ -47,7 +71,8 @@ fn genexpr(S *InstStream, ex *Expr) IRValue {
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))));
+ let inst = S->mkinst3({t}, :Val(res), :Val(lhs), :Val(rhs));
+ S->push(inst);
return res;
} ]
@@ -60,47 +85,104 @@ fn genexpr(S *InstStream, ex *Expr) IRValue {
case UnOp u;
switch u.op {
case :neg; genunop(u, ex.ty->is(:Int) ? :neg : :fneg);
+ case :not; genunop(u, :not);
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, !ex.ty->is(:Flo) ? :add : :fadd);
+ case '-'; genbinop(b, !ex.ty->is(:Flo) ? :sub : :fsub);
+ case '*'; genbinop(b, !ex.ty->is(:Flo) ? :mul : :fmul);
+ case '/'; genbinop(b, !ex.ty->is(:Flo) ? :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 '=='; genbinop(b, :eq);
+ case '!='; genbinop(b, :neq);
+ case '<'; genbinop(b, :lt);
+ case '<='; genbinop(b, :lteq);
}
+ case Cond c;
+ let test = genexpr(S, c.test);
+ let beqz = S->mkinst1({:beqz}, :Val(test));
+ S->push(beqz);
+ let t = genexpr(S, c.t);
+ let res = IRValue{ex.ty, :Tmp(tmpid++)};
+ let inst = S->mkinst2({:copy}, :Val(res), :Val(t));
+ S->push(inst);
+ let b = S->mkinst({:b}, 0);
+ S->push(b);
+ S->pushnop();
+ beqz.branch = S.tail;
+ let f = genexpr(S, c.f);
+ let inst = S->mkinst2({:copy}, :Val(res), :Val(f));
+ S->push(inst);
+ S->pushnop();
+ b.branch = S.tail;
+ return res;
+
+
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);
+ let n = c.args.#len;
+ let inst = S->mkinst({:call, .call_nargs: n}, n + 2);
+ inst.args[1] = :Fn(c.lhs.u.Symbol);
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]));
+ inst.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 {
}
-
+ let res = IRValue{ex.ty, :Tmp(tmpid++)};
+ inst.args[0] = :Val(res);
+ return res;
+ case Symbol decl;
+ if decl.u.#tag == :Let {
+ return {ex.ty, :Local(decl)};
+ } else {
+ return {ex.ty, :Global(decl)};
+ }
}
assert(#f, "NYI ex");
}
fn genstmt(S *InstStream, stmt *Stmt) void {
switch stmt.u {
+ case Block block;
+ genblock(S, block);
+
case Expr *ex;
genexpr(S, ex);
+
+ case If If;
+ let t = genexpr(S, &If.test);
+ let beqz = S->mkinst1({:beqz}, :Val(t));
+ S->push(beqz);
+ genblock(S, If.t);
+ if If.f.#ptr {
+ let b = S->mkinst({:b}, 0);
+ S->push(b);
+ S->pushnop();
+ beqz.branch = S.tail;
+ genblock(S, If.f);
+ S->pushnop();
+ b.branch = S.tail;
+ } else {
+ S->pushnop();
+ beqz.branch = S.tail;
+ }
+
+ case Return retex;
+ if retex->empty() {
+ S->push(S->mkinst({:ret0}, 0));
+ } else {
+ let inst = S->mkinst1({:ret}, :Val(genexpr(S, &retex.Some)));
+ S->push(inst);
+ }
+
case else
assert(#f, "NYI st");
}
@@ -116,7 +198,7 @@ extern fn ir_genfn(IR *IRCtx, f *Fn) void {
let stream InstStream = {.IR: IR};
genblock(&stream, f.body.Some);
- stream->push(mkinstr(&stream, :ret0, {}));
+ stream->push(stream->mkinst({:ret0}, 0));
efmt("----------------------\n");
efmt("function %s.%d:\n", container_of(f, Decl, u.Fn).name, f.id);