diff options
| author | 2022-08-20 11:06:38 +0200 | |
|---|---|---|
| committer | 2022-08-20 11:06:38 +0200 | |
| commit | 46e1f128fd310bd29a2b4335b36c60d6cc0aa3a7 (patch) | |
| tree | feb93a69cf93773d0542435ae09c76de04e509c8 /src/irgen.cff | |
| parent | df41a4512932f1312e4725d0409757a683b091ed (diff) | |
initial work on IR
Diffstat (limited to 'src/irgen.cff')
| -rw-r--r-- | src/irgen.cff | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/src/irgen.cff b/src/irgen.cff new file mode 100644 index 0000000..1ba080d --- /dev/null +++ b/src/irgen.cff @@ -0,0 +1,124 @@ +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); +} |