aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/hello-world.cff2
-rw-r--r--src/cffc.hff2
-rw-r--r--src/ir.hff15
-rw-r--r--src/irdump.cff85
-rw-r--r--src/irgen.cff134
-rw-r--r--src/parse.cff14
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 {
diff --git a/src/ir.hff b/src/ir.hff
index 987db3b..ec949ec 100644
--- a/src/ir.hff
+++ b/src/ir.hff
@@ -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++
}});
}
}