import "ir.hff"; import "common.hff"; extern fn ir_genstatic(IR *IRCtx, decl *Decl) void { } struct InstStream { IR *IRCtx, head *IRInst, tail *IRInst, fn push(S *InstStream, inst *IRInst) void { if S.tail { S.tail.next = inst; } else { S.head = inst; } S.tail = 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]; } return inst; } defmacro mkslice(Ty, ...args) [ (as([]Ty){args})[0::] ] fn genblock(S *InstStream, block [#]Stmt) 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++)}; S->push(mkinstr(S, (t), mkslice(IRArg, :Val(res), :Val(child)))); 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++)}; S->push(mkinstr(S, (t), mkslice(IRArg, :Val(res), :Val(lhs), :Val(rhs)))); 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 :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, :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 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); 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])); } let inst = mkinstr(S, :call, args); inst.call_nargs = n; S->push(inst); return res; } else { } } assert(#f, "NYI ex"); } fn genstmt(S *InstStream, stmt *Stmt) void { switch stmt.u { case Expr *ex; genexpr(S, ex); case else assert(#f, "NYI st"); } } fn genblock(S *InstStream, block [#]Stmt) void { foreach_ptr(st, _, block) { genstmt(S, st); } } extern fn ir_genfn(IR *IRCtx, f *Fn) void { let stream InstStream = {.IR: IR}; genblock(&stream, f.body.Some); stream->push(mkinstr(&stream, :ret0, {})); efmt("----------------------\n"); efmt("function %s.%d:\n", container_of(f, Decl, u.Fn).name, f.id); irdump(stream.head); }