diff options
| -rw-r--r-- | examples/hello-world.cff | 2 | ||||
| -rw-r--r-- | src/cffc.hff | 2 | ||||
| -rw-r--r-- | src/ir.hff | 15 | ||||
| -rw-r--r-- | src/irdump.cff | 85 | ||||
| -rw-r--r-- | src/irgen.cff | 134 | ||||
| -rw-r--r-- | src/parse.cff | 14 |
6 files changed, 196 insertions, 56 deletions
diff --git a/examples/hello-world.cff b/examples/hello-world.cff index 42258ab..c4a99ea 100644 --- a/examples/hello-world.cff +++ b/examples/hello-world.cff @@ -1,6 +1,6 @@ import "libc.hff"; extern fn main(argc int, argv *const *const u8) int { - printf("hello %d", 42); + printf("hello %d", argc + 42); } diff --git a/src/cffc.hff b/src/cffc.hff index e10602d..31af5fb 100644 --- a/src/cffc.hff +++ b/src/cffc.hff @@ -131,6 +131,7 @@ struct Parser { curexpan *Expan, expanno int, loopid int, + varid int, targty *const Type, tokloc Loc, curloc Loc, @@ -240,6 +241,7 @@ struct Var { ini Option<Expr>, fwd bool, fnid int, + id int, } struct MacroCase { @@ -18,6 +18,8 @@ struct IRValue { BImm bool, Null, Tmp int, + Local *Decl, + Global *Decl, } } @@ -28,7 +30,9 @@ enum union IRArg { } enum IRInstT { + nop, neg, + not, compl, fneg, add, @@ -46,15 +50,24 @@ enum IRInstT { fsub, fmul, fdiv, + eq, + neq, + lt, + lteq, copy, + load, + store, call, + b, + beqz, ret0, + ret, } struct IRInst { t IRInstT, next *IRInst, - cond *IRInst, + branch *IRInst, call_nargs int, args [0]IRArg, } diff --git a/src/irdump.cff b/src/irdump.cff index 4147c8a..9d9318b 100644 --- a/src/irdump.cff +++ b/src/irdump.cff @@ -1,5 +1,6 @@ import "ir.hff"; import "common.hff"; +import "map.hff"; fn dump(fmt *const u8, ...) void { let ap va_list #?; @@ -31,9 +32,13 @@ fn dump(fmt *const u8, ...) void { efmt("#null"); case Tmp t; efmt("%%%d", t); + case Local l; + efmt("$%s.%d", l.name, l.u.Let.id); + case Global g; + efmt("@%s.%d", g.name, g.u.Static.id); } case Ty ty; efmt("%t", ty); - case Fn decl; efmt("%s", decl.name); + case Fn decl; efmt("@%s", decl.name); case else assert(#f, "arg? %d", arg.#tag); } case 't'; @@ -45,39 +50,59 @@ fn dump(fmt *const u8, ...) void { ap->end(); } -extern fn irdump(a *IRInst) void { - if a == #null { return; } +extern fn irdump(inst *IRInst) void { + let labels Map<*IRInst, int, struct { + fn hash(a *IRInst) u32 { return as(iptrint)a; } + fn eq(a *IRInst, b *IRInst) bool { return a == b; } + }> = {}; + defer labels->clear(); + let labid = 0; + for let a = inst; a; a = a.next { + if a.branch { + let slot = labels->get_slot(a.branch); + if *slot == 0 { + *slot = ++labid; + } + } + } - dump(" "); - #'dump do { + + #'dump for ; inst; inst = inst.next { + let label = labels->get(inst); + if label { + dump(".L%d:\t", *label); + } else { + dump("\t"); + } defmacro exprinst(tag, nam, n) [ - if a.t == (tag) { - dump("%%%d(%t) = " ## nam ## " ", a.args[0].Val.u.Tmp, a.args[0].Val.ty); + if inst.t == (tag) { + dump("%%%d(%t) = " ## nam ## " ", inst.args[0].Val.u.Tmp, inst.args[0].Val.ty); for let $i = 1; $i < (n); ++$i { - dump("%a", a.args[$i]); + dump("%a", inst.args[$i]); if $i < (n) - 1 { dump(", "); } } dump("\n"); - break #'dump; + continue #'dump; } ] defmacro stmtinst(tag, nam, n) [ - if a.t == (tag) { + if inst.t == (tag) { dump(nam##" "); for let $i = 0; $i < (n); ++$i { - dump("%a", a.args[$i]); + dump("%a", inst.args[$i]); if $i < (n) - 1 { dump(", "); } } dump("\n"); - break #'dump; + continue #'dump; } ] exprinst(:neg, "neg", 2) + exprinst(:not, "not", 2) exprinst(:compl, "compl", 2) exprinst(:fneg, "fneg", 2) exprinst(:add, "add", 3); @@ -91,29 +116,41 @@ extern fn irdump(a *IRInst) void { exprinst(:lsl, "lsl", 3); exprinst(:lsr, "lsr", 3); exprinst(:asr, "asr", 3); + exprinst(:eq, "eq", 3); + exprinst(:neq, "neq", 3); + exprinst(:lt, "lt", 3); + exprinst(:lteq, "lteq", 3); exprinst(:fadd, "fadd", 3); exprinst(:fsub, "fsub", 3); exprinst(:fmul, "fmul", 3); exprinst(:fdiv, "fdiv", 3); - if a.t == :call { - let fnty = a.args[1].Fn.u.Fn.ty.u.Fn; - dump("%%%d(%t) = call %a, ", a.args[0].Val.u.Tmp, a.args[0].Val.ty, a.args[1]); - let n = a.call_nargs; + if inst.t == :call { + let fnty = inst.args[1].Fn.u.Fn.ty.u.Fn; + dump("%%%d(%t) = call %a, ", inst.args[0].Val.u.Tmp, inst.args[0].Val.ty, inst.args[1]); + let n = inst.call_nargs; for let i = 0; i < n; ++i { - dump("%a(%t)", a.args[i + 2], - i < fnty.params.#len ? fnty.params[i] : a.args[i + 2].Val.ty); + dump("%a(%t)", inst.args[i + 2], + i < fnty.params.#len ? fnty.params[i] : inst.args[i + 2].Val.ty); if i < n - 1 { dump(", "); } } dump("\n"); - break #'dump; + continue #'dump; } - + exprinst(:copy, "copy", 2) + stmtinst(:nop, "nop", 0); stmtinst(:ret0, "ret", 0); + stmtinst(:ret, "ret", 1); + if inst.t == :beqz { + dump("beqz %a, .L%d\n", inst.args[0], *labels->get(inst.branch)); + continue #'dump; + } + if inst.t == :b { + dump("b .L%d\n", *labels->get(inst.branch)); + continue #'dump; + } - assert(#f, "inst? %d\n", a.t); - } while #f; - - irdump(a.next); + assert(#f, "inst? %d\n", inst.t); + }; } diff --git a/src/irgen.cff b/src/irgen.cff index 1ba080d..c0c4a16 100644 --- a/src/irgen.cff +++ b/src/irgen.cff @@ -4,6 +4,9 @@ import "common.hff"; extern fn ir_genstatic(IR *IRCtx, decl *Decl) void { } +struct InstStream; + + struct InstStream { IR *IRCtx, head *IRInst, @@ -16,19 +19,39 @@ struct InstStream { } 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 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]; + 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 pushnop(S *InstStream) void { + S->push(S->mkinst({:nop}, 0)); } - return inst; } -defmacro mkslice(Ty, ...args) [ (as([]Ty){args})[0::] ] fn genblock(S *InstStream, block [#]Stmt) void; fn genexpr(S *InstStream, ex *Expr) IRValue { @@ -39,7 +62,8 @@ fn genexpr(S *InstStream, ex *Expr) IRValue { 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)))); + let inst = S->mkinst2({t}, :Val(res), :Val(child)); + S->push(inst); return res; } ] @@ -47,7 +71,8 @@ fn genexpr(S *InstStream, ex *Expr) IRValue { 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)))); + let inst = S->mkinst3({t}, :Val(res), :Val(lhs), :Val(rhs)); + S->push(inst); return res; } ] @@ -60,47 +85,104 @@ fn genexpr(S *InstStream, ex *Expr) IRValue { 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 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, !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 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); + S->pushnop(); + beqz.branch = S.tail; + let f = genexpr(S, c.f); + let inst = S->mkinst2({:copy}, :Val(res), :Val(f)); + S->push(inst); + S->pushnop(); + b.branch = S.tail; + return res; + + 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); + 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 { - args[1] = :Fn(c.lhs.u.Symbol); for let i = 0; i < n; ++i { - args[i + 2] = :Val(genexpr(S, &c.args[i])); + inst.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 { } - + 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 If If; + let t = genexpr(S, &If.test); + let beqz = S->mkinst1({:beqz}, :Val(t)); + S->push(beqz); + genblock(S, If.t); + if If.f.#ptr { + let b = S->mkinst({:b}, 0); + S->push(b); + S->pushnop(); + beqz.branch = S.tail; + genblock(S, If.f); + S->pushnop(); + b.branch = S.tail; + } else { + S->pushnop(); + beqz.branch = S.tail; + } + + case Return retex; + if retex->empty() { + S->push(S->mkinst({:ret0}, 0)); + } else { + let inst = S->mkinst1({:ret}, :Val(genexpr(S, &retex.Some))); + S->push(inst); + } + case else assert(#f, "NYI st"); } @@ -116,7 +198,7 @@ extern fn ir_genfn(IR *IRCtx, f *Fn) void { let stream InstStream = {.IR: IR}; genblock(&stream, f.body.Some); - stream->push(mkinstr(&stream, :ret0, {})); + stream->push(stream->mkinst({:ret0}, 0)); efmt("----------------------\n"); efmt("function %s.%d:\n", container_of(f, Decl, u.Fn).name, f.id); diff --git a/src/parse.cff b/src/parse.cff index e32b758..43c4e7d 100644 --- a/src/parse.cff +++ b/src/parse.cff @@ -692,7 +692,7 @@ fn parseagg(P *Parser, loc Loc, kind AggKind, name *const u8, retdecl **Decl) *c if decl { switch decl.u { case Ty ty; - if !ty->is(:Agg) or !ty.u.Agg.fwd or ty.u.Agg.kind != kind { + if !ty->is(:Agg) or !ty.u.Agg.fwd or ty.u.Agg.kind != kind or !streq(ty.u.Agg.name, name) { decl = #null; } case else @@ -701,6 +701,7 @@ fn parseagg(P *Parser, loc Loc, kind AggKind, name *const u8, retdecl **Decl) *c } let ty = decl ? decl.u.Ty : interntype({ .u: :Agg { kind, name, id++ }}); let ty = as(*Type)ty; + let constty = as(*Type)constify(ty); let agg = &ty.u.Agg; if name != #null { @@ -754,6 +755,8 @@ fn parseagg(P *Parser, loc Loc, kind AggKind, name *const u8, retdecl **Decl) *c ty.size = size; ty.align = align; agg.flds = flds.dat[0::flds.len]; + *constty = *ty; + constty.konst = #t; if kind == :EUnion { // add enum tag field on top and offset every other field down static id int = 0; @@ -780,6 +783,8 @@ fn parseagg(P *Parser, loc Loc, kind AggKind, name *const u8, retdecl **Decl) *c ty.size += off; align = MAX(align, enumty.align); ty.size = ALIGNUP(ty.size, align); + *constty = *ty; + constty.konst = #t; foreach_ptr(fld, _, agg.flds) { fld.off += off; @@ -787,6 +792,7 @@ fn parseagg(P *Parser, loc Loc, kind AggKind, name *const u8, retdecl **Decl) *c } if havedecls { agg.decls = mkenv(P.curenv, P.alloc); + constty.u.Agg.decls = agg.decls; pushenv(P, agg.decls); while !lexmatch(P, #null, '}') { parsedecls(P, tok.loc, #null, #null, #{toplevel} #f); @@ -2178,7 +2184,7 @@ fn psteuswitch(P *Parser, loc Loc, test Expr) Stmt { } pushenv(P, env); putdecl(P, tok.loc, { - c.capt, tok.loc, .u: :Let { c.captty = ty, :None, #f, P.curfn.id } + c.capt, tok.loc, .u: :Let { c.captty = ty, :None, #f, P.curfn.id, P.varid++ } }); } lexexpect(P, ';'); @@ -2390,7 +2396,7 @@ fn parsevardecl(P *Parser, toplevel bool, externp bool, letp bool, yield DeclYie ty = constify(ty); } - let decl Decl = { name, tok.loc, externp, :Let { ty, ini, fwd, 0 } }; + let decl Decl = { name, tok.loc, externp, :Let { ty, ini, fwd, P.curfn ? P.curfn.id : 0, P.varid++ } }; if !letp { decl.u.#tag = :Static; } @@ -2438,7 +2444,7 @@ fn parsefn(P *Parser, loc Loc, externp bool, name *const u8) *Decl { foreach(name, i, Fn.paramnames) { if name { putdecl(P, loc, { name, loc, .u: :Let { - Fn.ty.u.Fn.params[i], :None, #f, Fn.id, + Fn.ty.u.Fn.params[i], :None, #f, Fn.id, P.varid++ }}); } } |