aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bootstrap/cgen.c7
-rw-r--r--bootstrap/parse.c5
-rw-r--r--examples/hello-world.cff2
-rw-r--r--src/cffc.hff10
-rw-r--r--src/fmt.cff6
-rw-r--r--src/ir.cff10
-rw-r--r--src/ir.hff62
-rw-r--r--src/irdump.cff119
-rw-r--r--src/irgen.cff124
-rw-r--r--src/parse.cff7
10 files changed, 345 insertions, 7 deletions
diff --git a/bootstrap/cgen.c b/bootstrap/cgen.c
index 5fae699..e4ba1fd 100644
--- a/bootstrap/cgen.c
+++ b/bootstrap/cgen.c
@@ -246,7 +246,10 @@ genexpr(struct expr *ex) {
pri(")");
break;
case Eas:
- pri("((%t)%e)", ex->ty, ex->child);
+ if (ex->ty->t != TYarr)
+ pri("((%t)%e)", ex->ty, ex->child);
+ else
+ pri("(%e)", ex->child);
break;
case Eenumval:
pri("/*%s:%s*/", ex->ty->enu.name, ex->enu.vname);
@@ -341,7 +344,7 @@ genstmt(struct blockstmt *block, struct stmt *stmt) {
&& (decl.var.ini->t == Ezeroini || decl.var.ini->t == Eini))
{
geniniex(decl.var.ini);
- } else if (decl.var.ty->t == TYeunion) {
+ } else if (decl.var.ini->t == Eeuini) {
geneuiniex(decl.var.ini);
} else {
pri("%e", decl.var.ini);
diff --git a/bootstrap/parse.c b/bootstrap/parse.c
index 371289f..91c7567 100644
--- a/bootstrap/parse.c
+++ b/bootstrap/parse.c
@@ -1644,7 +1644,10 @@ pexprefix(struct parser *P) {
ex = pexprefix(P);
from = ex.ty;
- if (typeof2(to, from)) ;
+ if (to->t == TYarr && to->length < 0 && ex.t == Eini) {
+ ex.ty = to = mkarraytype(to->child, ex.ini.maxn + 1);
+ }
+ else if (typeof2(to, from)) ;
else if (to->t == TYint && from->t == TYptr && to->size == from->size) ;
else if (from->t == TYint && to->t == TYptr && to->size == from->size) ;
else if (from->t == TYptr && to->t == TYptr) ;
diff --git a/examples/hello-world.cff b/examples/hello-world.cff
index 3eb198c..42258ab 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 world\n");
+ printf("hello %d", 42);
}
diff --git a/src/cffc.hff b/src/cffc.hff
index abc00ae..e10602d 100644
--- a/src/cffc.hff
+++ b/src/cffc.hff
@@ -20,7 +20,7 @@ struct Loc {
enum TokT : i32 {
// !sorted
kw_alignof, kw_and, kw_as, kw_break, kw_case, kw_const,
- kw_continue, kw_def, kw_defmacro, kw_do,
+ kw_continue, kw_def, kw_defer, kw_defmacro, kw_do,
kw_else, kw_enum, kw_extern, kw_fn,
kw_for, kw_if, kw_import, kw_let, kw_offsetof,
kw_or, kw_return, kw_sizeof, kw_static,
@@ -118,8 +118,10 @@ struct Type {
struct Fn;
struct Expan;
+struct IRCtx;
struct Parser {
fp *FILE,
+ irctx *IRCtx,
alloc *Allocator,
tlalloc *Allocator,
curfile *const u8,
@@ -433,3 +435,9 @@ extern fn envfree(*Env) void;
// fold.cff
extern fn fold(*Expr) bool;
+
+// ir*.cff
+extern fn mkirctx(*Allocator) *IRCtx;
+extern fn ir_genstatic(*IRCtx, *Decl) void;
+extern fn ir_genfn(*IRCtx, *Fn) void;
+extern fn ir_free(*IRCtx) void;
diff --git a/src/fmt.cff b/src/fmt.cff
index 91f13d8..8c0f6a4 100644
--- a/src/fmt.cff
+++ b/src/fmt.cff
@@ -211,6 +211,8 @@ extern fn vpfmt(proc *fn(u8, *void) void, parg *void, fmt *const u8, ap va_list)
let quote = #f;
for ;; {
switch (c = *++fmt) {
+ case '%';
+ fprintf(stderr, "%%");
case 'q';
quote = #t;
continue;
@@ -223,6 +225,10 @@ extern fn vpfmt(proc *fn(u8, *void) void, parg *void, fmt *const u8, ap va_list)
case 'z';
sprintf(buf, "%zu", ap->arg(usize));
ps(buf);
+ case 'f';
+ sprintf(buf, "%.17f", ap->arg(f64));
+ ps(buf);
+
case 'p';
sprintf(buf, "%p", ap->arg(*void));
ps(buf);
diff --git a/src/ir.cff b/src/ir.cff
new file mode 100644
index 0000000..8b28746
--- /dev/null
+++ b/src/ir.cff
@@ -0,0 +1,10 @@
+import "ir.hff";
+
+extern fn mkirctx(alloc *Allocator) *IRCtx {
+ let ctx *IRCtx = anew(alloc, IRCtx);
+ ctx.alloc = alloc;
+ return ctx;
+}
+
+extern fn ir_free(IR *IRCtx) void {
+}
diff --git a/src/ir.hff b/src/ir.hff
new file mode 100644
index 0000000..987db3b
--- /dev/null
+++ b/src/ir.hff
@@ -0,0 +1,62 @@
+import "cffc.hff";
+
+struct IRCtx {
+ alloc *Allocator,
+}
+
+struct IRInst;
+struct IRFn {
+ body *IRInst
+}
+
+struct IRValue {
+ ty *const Type,
+ u enum union {
+ IImm i64,
+ FImm f64,
+ SImm [#]const u8,
+ BImm bool,
+ Null,
+ Tmp int,
+ }
+}
+
+enum union IRArg {
+ Val IRValue,
+ Ty *const Type,
+ Fn *Decl,
+}
+
+enum IRInstT {
+ neg,
+ compl,
+ fneg,
+ add,
+ sub,
+ mul,
+ div,
+ mod,
+ band,
+ bor,
+ xor,
+ lsl,
+ lsr,
+ asr,
+ fadd,
+ fsub,
+ fmul,
+ fdiv,
+ copy,
+ call,
+ ret0,
+}
+
+struct IRInst {
+ t IRInstT,
+ next *IRInst,
+ cond *IRInst,
+ call_nargs int,
+ args [0]IRArg,
+}
+
+extern fn irdump(*IRInst) void;
diff --git a/src/irdump.cff b/src/irdump.cff
new file mode 100644
index 0000000..4147c8a
--- /dev/null
+++ b/src/irdump.cff
@@ -0,0 +1,119 @@
+import "ir.hff";
+import "common.hff";
+
+fn dump(fmt *const u8, ...) void {
+ let ap va_list #?;
+ ap->start(fmt);
+ for let c = *fmt; c != 0; c = *++fmt {
+ if c != '%' {
+ fputc(c, stderr);
+ continue;
+ }
+ switch (c = *++fmt) {
+ case '%';
+ fputc('%', stderr);
+ case 'd';
+ efmt("%d", ap->arg(int));
+ case 'a';
+ let arg = ap->arg(IRArg);
+ switch arg {
+ case Val val;
+ switch val.u {
+ case IImm i;
+ efmt("%I", i);
+ case FImm f;
+ efmt("%f", f);
+ case SImm s;
+ efmt("%S", s);
+ case BImm b;
+ efmt("%s", b ? "#t" : "#f");
+ case Null;
+ efmt("#null");
+ case Tmp t;
+ efmt("%%%d", t);
+ }
+ case Ty ty; efmt("%t", ty);
+ case Fn decl; efmt("%s", decl.name);
+ case else assert(#f, "arg? %d", arg.#tag);
+ }
+ case 't';
+ efmt("%t", ap->arg(*Type));
+ case else
+ assert(#f, "bad fmt %c", c);
+ }
+ }
+ ap->end();
+}
+
+extern fn irdump(a *IRInst) void {
+ if a == #null { return; }
+
+ dump(" ");
+ #'dump do {
+ defmacro exprinst(tag, nam, n) [
+ if a.t == (tag) {
+ dump("%%%d(%t) = " ## nam ## " ", a.args[0].Val.u.Tmp, a.args[0].Val.ty);
+ for let $i = 1; $i < (n); ++$i {
+ dump("%a", a.args[$i]);
+ if $i < (n) - 1 {
+ dump(", ");
+ }
+ }
+ dump("\n");
+ break #'dump;
+ }
+ ]
+ defmacro stmtinst(tag, nam, n) [
+ if a.t == (tag) {
+ dump(nam##" ");
+ for let $i = 0; $i < (n); ++$i {
+ dump("%a", a.args[$i]);
+ if $i < (n) - 1 {
+ dump(", ");
+ }
+ }
+ dump("\n");
+ break #'dump;
+ }
+ ]
+
+ exprinst(:neg, "neg", 2)
+ exprinst(:compl, "compl", 2)
+ exprinst(:fneg, "fneg", 2)
+ exprinst(:add, "add", 3);
+ exprinst(:sub, "sub", 3);
+ exprinst(:mul, "mul", 3);
+ exprinst(:div, "div", 3);
+ exprinst(:mod, "mod", 3);
+ exprinst(:band, "band", 3);
+ exprinst(:bor, "bor", 3);
+ exprinst(:xor, "xor", 3);
+ exprinst(:lsl, "lsl", 3);
+ exprinst(:lsr, "lsr", 3);
+ exprinst(:asr, "asr", 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;
+ 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);
+ if i < n - 1 {
+ dump(", ");
+ }
+ }
+ dump("\n");
+ break #'dump;
+ }
+
+ stmtinst(:ret0, "ret", 0);
+
+ assert(#f, "inst? %d\n", a.t);
+ } while #f;
+
+ irdump(a.next);
+}
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);
+}
diff --git a/src/parse.cff b/src/parse.cff
index f2bbb41..e32b758 100644
--- a/src/parse.cff
+++ b/src/parse.cff
@@ -142,7 +142,7 @@ fn eatspaces(P *Parser) void {
// !sorted
extern static keyword2str [NUM_KEYWORDS]*const u8 = {
"alignof", "and", "as", "break", "case", "const",
- "continue", "def", "defmacro", "do",
+ "continue", "def", "defer", "defmacro", "do",
"else", "enum", "extern", "fn",
"for", "if", "import", "let", "offsetof",
"or", "return", "sizeof", "static",
@@ -1510,7 +1510,7 @@ fn pexpostfix(P *Parser) Expr {
if args.len >= params.#len and !Fn.variadic {
fatal(P, ex.loc, "too many args (%z, expected %z)", args.len, params.#len);
}
- if args.len < params.#len and !typematchestarg(*param, ex.ty) {
+ if args.len <= params.#len and !typematchestarg(*param, ex.ty) {
err(P, ex.loc, "function call argument type mismatch (%t, expected %t)",
ex.ty, *param);
}
@@ -2444,6 +2444,7 @@ fn parsefn(P *Parser, loc Loc, externp bool, name *const u8) *Decl {
}
Fn.body = :Some(parseblock(P));
popenv(P);
+ ir_genfn(P.irctx, Fn);
(as(*Arena)P.alloc.a)->destroy();
}
}
@@ -2752,6 +2753,7 @@ fn parsedecls(P *Parser, loc Loc, yield DeclYielder, yarg *void, toplevel bool)
if a.yield {
a.yield(decl, a.yarg);
}
+ ir_genstatic(a.P.irctx, decl);
}
parsevardecl(P, toplevel, externp, #{let?} #t, &varyield, &Arg { P, externp, toplevel, yield, yarg });
return;
@@ -2835,6 +2837,7 @@ extern fn parse(P *Parser) [#]Decl {
let alloc = Allocator { &aralloc, &Arena:allocf, #null };
let decls Vec<Decl> = {};
P.alloc = (P.tlalloc = &alloc);
+ P.irctx = mkirctx(P.alloc);
P.curenv = mkenv(#null, P.alloc);
if primenv == #null {
primenv = mkenv(#null, P.alloc);