diff options
Diffstat (limited to 'src/irgen.cff')
| -rw-r--r-- | src/irgen.cff | 139 |
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)); |