aboutsummaryrefslogtreecommitdiff
path: root/src/irgen.cff
diff options
context:
space:
mode:
Diffstat (limited to 'src/irgen.cff')
-rw-r--r--src/irgen.cff139
1 files changed, 125 insertions, 14 deletions
diff --git a/src/irgen.cff b/src/irgen.cff
index c0c4a16..1cd5172 100644
--- a/src/irgen.cff
+++ b/src/irgen.cff
@@ -1,16 +1,22 @@
import "ir.hff";
import "common.hff";
+import "map.hff";
extern fn ir_genstatic(IR *IRCtx, decl *Decl) void {
}
-struct InstStream;
-
+struct IntTraits {
+ fn hash(a int) u32 { return (a * 7128347) + 972183; }
+ fn eq(a int, b int) bool { return a == b; }
+}
struct InstStream {
IR *IRCtx,
head *IRInst,
tail *IRInst,
+ loopbrks Map<int, *IRInst, IntTraits>,
+ loopconts Map<int, *IRInst, IntTraits>,
+
fn push(S *InstStream, inst *IRInst) void {
if S.tail {
S.tail.next = inst;
@@ -47,8 +53,9 @@ struct InstStream {
return inst;
}
- fn pushnop(S *InstStream) void {
+ fn pushnop(S *InstStream) *IRInst {
S->push(S->mkinst({:nop}, 0));
+ return S.tail;
}
}
@@ -87,6 +94,26 @@ fn genexpr(S *InstStream, ex *Expr) IRValue {
case :neg; genunop(u, ex.ty->is(:Int) ? :neg : :fneg);
case :not; genunop(u, :not);
case :compl; genunop(u, :compl);
+ case :deref; genunop(u, :load);
+ case :preinc, :predec;
+ let one = u.op == :preinc ? 1 : -1;
+ switch u.ex.u {
+ case Symbol decl;
+ let ex = genexpr(S, u.ex);
+ let inced = IRValue{ex.ty, .u: :Tmp(tmpid++)};
+ let rhs = S->mkinst3({:add}, :Val(inced),
+ :Val(ex), :Val{ty_int, :IImm(one)});
+ S->push(rhs);
+ let inst = S->mkinst2({:setvar}, :Val(ex), :Val(inced));
+ S->push(inst);
+ let ex = genexpr(S, u.ex);
+ if decl.u.#tag == :Let {
+ return {ex.ty, :Local(decl)};
+ } else {
+ return {ex.ty, :Global(decl)};
+ }
+ }
+
}
case BinOp b;
switch b.op {
@@ -104,6 +131,41 @@ fn genexpr(S *InstStream, ex *Expr) IRValue {
case '!='; genbinop(b, :neq);
case '<'; genbinop(b, :lt);
case '<='; genbinop(b, :lteq);
+ case '>';
+ let lhs = genexpr(S, (b).lhs);
+ let rhs = genexpr(S, (b).rhs);
+ let res = IRValue{ex.ty, .u: :Tmp(tmpid++)};
+ let inst = S->mkinst3({:lt}, :Val(res), :Val(rhs), :Val(lhs));
+ S->push(inst);
+ return res;
+ case '>=';
+ let lhs = genexpr(S, (b).lhs);
+ let rhs = genexpr(S, (b).rhs);
+ let res = IRValue{ex.ty, .u: :Tmp(tmpid++)};
+ let inst = S->mkinst3({:lteq}, :Val(res), :Val(rhs), :Val(lhs));
+ S->push(inst);
+ return res;
+ case '=';
+ switch b.lhs.u {
+ case Symbol decl;
+ let inst = S->mkinst2({:setvar}, :Val(genexpr(S, b.lhs)), :Val(genexpr(S, b.rhs)));
+ S->push(inst);
+ if decl.u.#tag == :Let {
+ return {ex.ty, :Local(decl)};
+ } else {
+ return {ex.ty, :Global(decl)};
+ }
+ case UnOp u;
+ assert(u.op == :deref, "deref?? unop=");
+ let child = genexpr(S, u.ex);
+ let inst = S->mkinst2({:store}, :Val(child), :Val(genexpr(S, b.rhs)));
+ S->push(inst);
+ let it = genexpr(S, b.lhs);
+ return it;
+
+ case else
+ assert(#f, "nyi =");
+ }
}
case Cond c;
let test = genexpr(S, c.test);
@@ -115,15 +177,12 @@ fn genexpr(S *InstStream, ex *Expr) IRValue {
S->push(inst);
let b = S->mkinst({:b}, 0);
S->push(b);
- S->pushnop();
- beqz.branch = S.tail;
+ beqz.branch = S->pushnop();
let f = genexpr(S, c.f);
let inst = S->mkinst2({:copy}, :Val(res), :Val(f));
S->push(inst);
- S->pushnop();
- b.branch = S.tail;
+ b.branch = S->pushnop();
return res;
-
case Call c;
let n = c.args.#len;
@@ -146,6 +205,7 @@ fn genexpr(S *InstStream, ex *Expr) IRValue {
return {ex.ty, :Global(decl)};
}
}
+
assert(#f, "NYI ex");
}
@@ -157,6 +217,14 @@ fn genstmt(S *InstStream, stmt *Stmt) void {
case Expr *ex;
genexpr(S, ex);
+ case Decl decl;
+ if decl.u.#tag == :Let and !decl.u.Let.ini->empty() {
+ let Let = &decl.u.Let;
+ let inst = S->mkinst2({:setvar}, :Val{Let.ty, :Local(decl)},
+ :Val(genexpr(S, &Let.ini.Some)));
+ S->push(inst);
+ }
+
case If If;
let t = genexpr(S, &If.test);
let beqz = S->mkinst1({:beqz}, :Val(t));
@@ -165,16 +233,57 @@ fn genstmt(S *InstStream, stmt *Stmt) void {
if If.f.#ptr {
let b = S->mkinst({:b}, 0);
S->push(b);
- S->pushnop();
- beqz.branch = S.tail;
+ beqz.branch = S->pushnop();
genblock(S, If.f);
- S->pushnop();
- b.branch = S.tail;
+ b.branch = S->pushnop();
} else {
- S->pushnop();
- beqz.branch = S.tail;
+ beqz.branch = S->pushnop();
}
+ case While loop;
+ let begin = S->pushnop();
+ let t = genexpr(S, &loop.test);
+ let beqz = S->mkinst1({:beqz}, :Val(t));
+ let b = S->mkinst({:b}, 0);
+ let end = S->mkinst({:nop}, 0);
+ S->push(beqz);
+ S.loopconts->put(loop.id, begin);
+ S.loopbrks->put(loop.id, end);
+ genblock(S, loop.body);
+ S->push(b);
+ b.branch = begin;
+ S->push(end);
+ beqz.branch = end;
+
+ case For loop;
+ genblock(S, loop.ini);
+ let begin = S->pushnop();
+ let t = genexpr(S, &loop.test);
+ let beqz = S->mkinst1({:beqz}, :Val(t));
+ let b = S->mkinst({:b}, 0);
+ let next = S->mkinst({:nop}, 0);
+ let end = S->mkinst({:nop}, 0);
+ S->push(beqz);
+ S.loopconts->put(loop.id, next);
+ S.loopbrks->put(loop.id, end);
+ genblock(S, loop.body);
+ S->push(next);
+ if !loop.next->empty() {
+ genexpr(S, &loop.next.Some);
+ }
+ S->push(b);
+ b.branch = begin;
+ S->push(end);
+ beqz.branch = end;
+
+ case Break id;
+ let jumpto = *S.loopbrks->get(id);
+ S->push(S->mkinst({:b, .branch: jumpto},0));
+
+ case Continue id;
+ let jumpto = *S.loopconts->get(id);
+ S->push(S->mkinst({:b, .branch: jumpto},0));
+
case Return retex;
if retex->empty() {
S->push(S->mkinst({:ret0}, 0));
@@ -196,6 +305,8 @@ fn genblock(S *InstStream, block [#]Stmt) void {
extern fn ir_genfn(IR *IRCtx, f *Fn) void {
let stream InstStream = {.IR: IR};
+ defer stream.loopbrks->clear();
+ defer stream.loopconts->clear();
genblock(&stream, f.body.Some);
stream->push(stream->mkinst({:ret0}, 0));