diff options
| author | 2022-08-20 16:38:41 +0200 | |
|---|---|---|
| committer | 2022-08-20 16:38:41 +0200 | |
| commit | fa8aaba64d206330959470e1ffbf0ad0c974456a (patch) | |
| tree | c7937134d4c003f13afa2ff560a8789c5d943fec /src | |
| parent | 0ede7e7f9d6235092d9e3ae2df8b25445fb89c38 (diff) | |
more IR (is it correct even. its so confusing)
Diffstat (limited to 'src')
| -rw-r--r-- | src/ir.hff | 1 | ||||
| -rw-r--r-- | src/irdump.cff | 8 | ||||
| -rw-r--r-- | src/irgen.cff | 139 |
3 files changed, 133 insertions, 15 deletions
@@ -55,6 +55,7 @@ enum IRInstT { lt, lteq, copy, + setvar, load, store, call, diff --git a/src/irdump.cff b/src/irdump.cff index 9d9318b..0942f87 100644 --- a/src/irdump.cff +++ b/src/irdump.cff @@ -138,8 +138,14 @@ extern fn irdump(inst *IRInst) void { dump("\n"); continue #'dump; } - exprinst(:copy, "copy", 2) stmtinst(:nop, "nop", 0); + exprinst(:copy, "copy", 2) + if inst.t == :setvar { + dump("set %a, %a\n", inst.args[0], inst.args[1]); + continue #'dump; + } + exprinst(:load, "load", 2) + stmtinst(:store, "store", 2) stmtinst(:ret0, "ret", 0); stmtinst(:ret, "ret", 1); if inst.t == :beqz { 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)); |