diff options
Diffstat (limited to 'src/irgen.cff')
| -rw-r--r-- | src/irgen.cff | 440 |
1 files changed, 0 insertions, 440 deletions
diff --git a/src/irgen.cff b/src/irgen.cff deleted file mode 100644 index c0ea1e1..0000000 --- a/src/irgen.cff +++ /dev/null @@ -1,440 +0,0 @@ -import "ir.hff"; -import "common.hff"; -import "map.hff"; - -extern fn ir_genstatic(IR *IRCtx, decl *Decl) void { - g_targ.B.genstaticf(g_targ.B, decl); -} - -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; - } else { - S.head = inst; - } - 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 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 mkinst4(S *InstStream, inst0 IRInst, a IRArg, b IRArg, c IRArg, d IRArg) *IRInst { - let inst = S->mkinst(inst0, 4); - inst.args[0] = a; - inst.args[1] = b; - inst.args[2] = c; - inst.args[3] = d; - return inst; - } - - fn pushnop(S *InstStream) *IRInst { - S->push(S->mkinst({:nop}, 0)); - return S.tail; - } -} - - -fn genblock(S *InstStream, block Block) 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++)}; - let inst = S->mkinst2({t}, :Val(res), :Val(child)); - S->push(inst); - 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++)}; - let inst = S->mkinst3({t}, :Val(res), :Val(lhs), :Val(rhs)); - S->push(inst); - 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 :not; genunop(u, :not); - case :compl; genunop(u, :compl); - case :deref; - let child = genexpr(S, (u).ex); - let res = IRValue{ex.ty, .u: :Tmp(tmpid++)}; - let inst = S->mkinst3({:load}, :Val(res), :Val(child), :Val{ty_int,:IImm(0)}); - S->push(inst); - return res; - 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); - return inced; - } - } - case BinOp b; - switch b.op { - 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 '>'; - 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 { // var = ex - case Symbol decl; - let r = genexpr(S, b.rhs); - let inst = S->mkinst2({:setvar}, :Val(genexpr(S, b.lhs)), :Val(r)); - S->push(inst); - return r; - case UnOp u; // *a = ex - assert(u.op == :deref, "deref?? unop="); - let child = genexpr(S, u.ex); - let r = genexpr(S, b.rhs); - let inst = S->mkinst3({:store}, :Val(child), :Val{ty_int,:IImm(0)}, :Val(r)); - S->push(inst); - return r; - case Index index; // a[b] = ex - let indexee = genexpr(S, index.lhs); - let index = genexpr(S, index.rhs); - let newval = genexpr(S, b.rhs); - S->push(S->mkinst3({:store}, :Val(indexee), :Val(index), :Val(newval))); - return newval; - case else - assert(#f, "nyi ="); - } - case '+=', '-=', '*=', '/=', '%=', '&=', '|=', '^=', '<<=', '>>='; - let o IRInstT = b.op == '+=' ? (ex.ty->is(:Flo) ? :fadd : :add) - : b.op == '-=' ? (ex.ty->is(:Flo) ? :fsub : :sub) - : b.op == '*=' ? (ex.ty->is(:Flo) ? :fmul : :mul) - : b.op == '/=' ? (ex.ty->is(:Flo) ? :fdiv : :div) - : b.op == '%=' ? :mod - : b.op == '&=' ? :band - : b.op == '|=' ? :bor - : b.op == '<<=' ? :lsl - : b.op == '>>=' ? (ex.ty.u.Int.sgn ? :asr : :lsr) : :nop; - switch b.lhs.u { - case Symbol decl; // var += ex - let lhs = genexpr(S, b.lhs); - let rhs = genexpr(S, b.rhs); - let new = IRValue{ex.ty, .u: :Tmp(tmpid++)}; - S->push(S->mkinst3({o}, :Val(new), :Val(lhs), :Val(rhs))); - let inst = S->mkinst2({:setvar}, :Val(lhs), :Val(new)); - S->push(inst); - return new; - } - - } - case Cast src; - let src = genexpr(S, src); - let ret = IRValue{ex.ty, .u: :Tmp(tmpid++)}; - switch { - case ex.ty->is(:Int) and src.ty->is(:Flo); - S->push(S->mkinst2({:ftrunc}, :Val(ret), :Val(src))); - - case ex.ty->is(:Flo) and src.ty->is(:Int); - S->push(S->mkinst2({:itof}, :Val(ret), :Val(src))); - - case ex.ty->is(:Int) and src.ty->is(:Int); - S->push(S->mkinst2({:copy}, :Val(ret), :Val(src))); - - case ex.ty->is(:Int) and src.ty->is(:Bool); - S->push(S->mkinst2({:copy}, :Val(ret), :Val(src))); - - case ex.ty->is(:Bool) and src.ty->is(:Int); - S->push(S->mkinst2({:copy}, :Val(ret), :Val(src))); - - case ex.ty->is(:Ptr) and src.ty->is(:Int); - S->push(S->mkinst2({:copy}, :Val(ret), :Val(src))); - - case ex.ty->is(:Int) and src.ty->is(:Ptr); - S->push(S->mkinst2({:copy}, :Val(ret), :Val(src))); - - case else - assert(#f, "bad cast"); - } - return ret; - - case Dot dot; - let lhs = genexpr(S, dot.lhs); - let res = IRValue{ex.ty, .u: :Tmp(tmpid++)}; - let inst = S->mkinst4({lhs.ty->is(:Ptr) ? :pgetelem : :getelem}, - :Val(res), :Val(lhs), :Val{ty_usize,:IImm(dot.fld.off)}, :Ty(ex.ty)); - S->push(inst); - return res; - - case SLen lhs; - let lhs = genexpr(S, lhs); - let res = IRValue{ex.ty, .u: :Tmp(tmpid++)}; - let inst = S->mkinst4({lhs.ty->is(:Ptr) ? :pgetelem : :getelem}, - :Val(res), :Val(lhs), :Val{ty_usize,:IImm(g_targ.ptrsize)}, - :Ty(ex.ty)); - S->push(inst); - return res; - - case SPtr lhs; - let lhs = genexpr(S, lhs); - let res = IRValue{ex.ty, .u: :Tmp(tmpid++)}; - let inst = S->mkinst4({lhs.ty->is(:Ptr) ? :pgetelem : :getelem}, - :Val(res), :Val(lhs), :Val{ty_usize,:IImm(0)}, :Ty(ex.ty)); - S->push(inst); - return res; - - case EUTag lhs; - let lhs = genexpr(S, lhs); - let res = IRValue{ex.ty, .u: :Tmp(tmpid++)}; - let inst = S->mkinst4({lhs.ty->is(:Ptr) ? :pgetelem : :getelem}, - :Val(res), :Val(lhs), :Val{ty_usize,:IImm(0)}, :Ty(ex.ty)); - S->push(inst); - return res; - - - case Index idx; - let i = genexpr(S, idx.lhs); - let off = genexpr(S, idx.rhs); - let res = IRValue{ex.ty, .u: :Tmp(tmpid++)}; - let inst = S->mkinst3({:load}, :Val(res), :Val(i), :Val(off)); - S->push(inst); - return res; - - 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); - beqz.branch = S->pushnop(); - let f = genexpr(S, c.f); - let inst = S->mkinst2({:copy}, :Val(res), :Val(f)); - S->push(inst); - b.branch = S->pushnop(); - return res; - - case Call c; - 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 { - for let i = 0; i < n; ++i { - inst.args[i + 2] = :Val(genexpr(S, &c.args[i])); - } - S->push(inst); - } 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 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; - #{ - %t = <test> - beqz %t, .L0 - <t> - b .L1 - .L0: - <f> - .L1: - } - let t = genexpr(S, &If.test); - let beqz = S->mkinst1({:beqz}, :Val(t)); - S->push(beqz); - genblock(S, If.t); - if If.f.sts.#ptr { - let b = S->mkinst({:b}, 0); - S->push(b); - beqz.branch = S->pushnop(); - genblock(S, If.f); - b.branch = S->pushnop(); - } else { - beqz.branch = S->pushnop(); - } - - case While loop; - #{ - .cont: - %t = <test> - beqz %t, .brk - <body> - b .cont - .brk: - } - 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); - assert(jumpto != #null, "no brk label %d", id); - S->push(S->mkinst({:b, .branch: *jumpto},0)); - - case Continue id; - let jumpto = S.loopconts->get(id); - assert(jumpto != #null, "no cont label %d", id); - S->push(S->mkinst({:b, .branch: *jumpto},0)); - - case Return *ret; - if ret.ex->empty() { - S->push(S->mkinst({:ret0}, 0)); - } else { - let inst = S->mkinst1({:ret}, :Val(genexpr(S, &ret.ex.Some))); - S->push(inst); - } - - case else - assert(#f, "NYI st"); - } -} - -fn genblock(S *InstStream, block Block) void { - foreach_ptr(st, _, block.sts) { - genstmt(S, st); - } -} - -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)); - - efmt("----------------------\n"); - efmt("function %s.%d:\n", container_of(f, Decl, u.Fn).name, f.id); - irdump(stream.head); -} |