aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-24 14:46:36 +0200
committerlemon <lsof@mailbox.org>2022-08-24 14:46:36 +0200
commit9f320002800b0a8b7601528334f97ba64182bdd6 (patch)
treeeef77343a2ffbd74916d305610ff1e758467840c
parent53fcd5e1647fb56511bbdd98925dd38a84fd7248 (diff)
more llvm
-rw-r--r--bootstrap/libc.hff2
-rw-r--r--examples/life.cff79
-rw-r--r--src/cffc.hff3
-rw-r--r--src/llvm.cff117
-rw-r--r--src/option.hff7
-rw-r--r--src/parse.cff19
6 files changed, 195 insertions, 32 deletions
diff --git a/bootstrap/libc.hff b/bootstrap/libc.hff
index 9b396e1..65874d5 100644
--- a/bootstrap/libc.hff
+++ b/bootstrap/libc.hff
@@ -3,4 +3,4 @@ extern fn qsort(base *void, nmemb usize, size usize,
compar *fn(l *const void, r *const void, _ *void) int) void;
struct FILE;
-extern static stderr FILE, stdin FILE;
+extern static stderr *FILE, stdin *FILE;
diff --git a/examples/life.cff b/examples/life.cff
new file mode 100644
index 0000000..cd1cc2e
--- /dev/null
+++ b/examples/life.cff
@@ -0,0 +1,79 @@
+import "libc.hff";
+
+def W = 60, H = 40;
+
+typedef Board [(W * H)/8]u8;
+static board Board = {};
+
+fn get(b *Board, x uint, y uint) bool {
+ x %= W; y %= H;
+ let idx = x + (y * W);
+ return (*b)[idx / 8] & (1 << (idx % 8)) != 0;
+}
+
+fn set(b *Board, x uint, y uint, set bool) void {
+ x %= W; y %= H;
+ let idx = x + (y * W);
+ (*b)[idx / 8] &= ~(1 << (idx % 8));
+ if set {
+ (*b)[idx / 8] |= (1 << (idx % 8));
+ }
+}
+
+fn next(b *Board) void {
+ let temp Board = *b;
+ for let y = 0; y < H; ++y {
+ for let x = 0; x < W; ++x {
+ defmacro C(ox,oy) [ (as(int)get(&temp, x + ox, y + oy)) ]
+ let n = C(-1,-1) + C(0,-1) + C(1,-1)
+ + C(-1, 0) + C(1, 0)
+ + C(-1, 1) + C(0, 1) + C(1, 1);
+
+ set(b, x, y, #f);
+ if get(&temp, x, y) {
+ set(b, x, y, n == 3);
+ } else if n == 2 {
+ set(b, x, y, #t);
+ } else if n == 3 {
+ set(b, x, y, #t);
+ }
+ }
+ }
+}
+
+fn draw(b *Board) void {
+ printf("\x1B[H\n");
+ printf("\n");
+ for let y = 0; y < H; ++y {
+ printf(" ");
+ for let x = 0; x < W; ++x {
+ if get(b, x, y) {
+ printf("W");
+ } else {
+ printf(" ");
+ }
+ }
+ printf(" \n");
+ }
+}
+
+extern fn time(*void) int;
+fn init(b *Board) void {
+ let rnd u32 = time(#null);
+ for let y = 0; y < H; ++y {
+ for let x = 0; x < W; ++x {
+ set(b, x, y, as(bool)((rnd >> 31) & 1));
+ rnd = (rnd * 134775813) + 1;
+ }
+ }
+}
+
+extern fn usleep(u32) void;
+extern fn main() void {
+ init(&board);
+ for ;; {
+ draw(&board);
+ usleep(100);
+ next(&board);
+ }
+}
diff --git a/src/cffc.hff b/src/cffc.hff
index 7e1e579..ca6ebea 100644
--- a/src/cffc.hff
+++ b/src/cffc.hff
@@ -483,7 +483,8 @@ extern fn ir_free(*IRCtx) void;
extern static g_asmbackend Backend;
// llvm.cff
-extern fn llvm_addfn(*Decl) void;
+extern fn llvm_addglobl(*Decl, staticp bool) void;
extern fn llvm_genfn(externp bool, name *const u8, f *Fn) void;
+extern fn llvm_genstatic(externp bool, name *const u8, var *Var) void;
extern fn llvm_init(*FILE) void;
extern fn llvm_fini() void;
diff --git a/src/llvm.cff b/src/llvm.cff
index d266cbb..57390a0 100644
--- a/src/llvm.cff
+++ b/src/llvm.cff
@@ -71,6 +71,7 @@ extern fn genagg(ty *const Type) void {
}
}
+fn gendata(ty *const Type, ex *Expr) void;
fn gen(fmt *const u8, ...) void {
let ap va_list #?;
ap->start(fmt);
@@ -88,7 +89,8 @@ fn gen(fmt *const u8, ...) void {
// case Ptr p; gen("%t*", p->is(:Void) ? ty_i8 : p);
case Ptr p; gen("ptr");
case Slice p; gen("{ %t, %t }", mkptrtype(p), ty_usize);
- case Arr arr; gen("[%z x %t]", arr.length, arr.child);
+ case Arr arr;
+ gen("[%z x %t]", arr.length, arr.child);
case Agg;
genagg(ty);
case Enum enu; pritype(enu.intty);
@@ -168,6 +170,11 @@ fn gen(fmt *const u8, ...) void {
}
case 't';
pritype(ap->arg(*Type));
+
+ case 'C';
+ let ty = ap->arg(*const Type);
+ let ex = ap->arg(*Expr);
+ gendata(ty, ex);
case else
assert(#f, "bad fmt '%c'", c);
@@ -212,13 +219,13 @@ fn genaddr(f *Fn, ex *Expr) Value {
let lhs Value #?;
if idx.lhs.ty->is(:Arr) {
let arr = genaddr(f, idx.lhs);
- lhs = mktmp(ex.ty);
+ lhs = mktmp(mkptrtype(ex.ty));
gen("\t%v = getelementptr %t, %t %v, i32 0, i32 0\n", lhs, arr.ty.u.Arr.child, arr.ty, arr);
} else {
lhs = genexpr(f, idx.lhs);
}
let rhs = genexpr(f, idx.rhs),
- addr = mktmp(ex.ty);
+ addr = mktmp(mkptrtype(ex.ty));
gen("\t%v = getelementptr %t, %t %v, %t %v\n", addr, ex.ty, lhs.ty, lhs, rhs.ty, rhs);
return addr;
@@ -253,7 +260,7 @@ fn genaddr(f *Fn, ex *Expr) Value {
}
return tmp;
}
- assert(#f, "genaddr");
+ assert(#f, "genaddr %d", ex.u.#tag);
}
fn convert(f *Fn, to *const Type, ex *Expr) Value {
@@ -312,6 +319,20 @@ fn convert(f *Fn, to *const Type, ex *Expr) Value {
case to->is(:Int) and from->is(:Flo);
return cvt(to.u.Int.sgn ? "fptosi" : "fptoui");
+ case to->is(:Int) and from->is(:Bool);
+ let t0 = mktmp(ty_i1);
+ gen("\t%v = icmp ne %t %v, 0\n", t0, ex.ty, genexpr(f, ex));
+ let t1 = mktmp(to);
+ gen("\t%v = zext %t %v to %t\n", t1, t0.ty, t0, t1.ty);
+ return t1;
+
+ case to->is(:Bool) and from->is(:Int);
+ let t0 = mktmp(ty_i1);
+ gen("\t%v = icmp ne %t %v, 0\n", t0, ex.ty, genexpr(f, ex));
+ let t1 = mktmp(to);
+ gen("\t%v = zext %t %v to %t\n", t1, t0.ty, t0, t1.ty);
+ return t1;
+
case to->is(:Ptr) and from->is(:Ptr);
let t = mktmp(to),
@@ -481,6 +502,9 @@ fn genexpr(f *Fn, ex *Expr) Value {
case '^='; return genassignop("xor", ex.ty, b.lhs, b.rhs);
case'<<='; return genassignop("shl", ex.ty, b.lhs, b.rhs);
case'>>='; return genassignop(ex.ty.u.Int.sgn ? "ashr" : "lshr", ex.ty, b.lhs, b.rhs);
+ // case 'and';
+ // case 'or';
+
case else
assert(#f, "binop? %c", b.op);
@@ -501,6 +525,11 @@ fn genexpr(f *Fn, ex *Expr) Value {
gen("\t%v = xor %t -1, %v\n", tmp, ex.ty, convert(f, ex.ty, un.ex));
return tmp;
+ case :not;
+ let tmp = mktmp(ex.ty);
+ gen("\t%v = xor %t 1, %v\n", tmp, ex.ty, convert(f, ex.ty, un.ex));
+ return tmp;
+
case :preinc, :predec;
let one = Value{ex.ty, :IImm(un.op == :preinc ? 1 : -1)};
let addr = genaddr(f, un.ex);
@@ -752,40 +781,46 @@ fn genblock(f *Fn, block Block) Option<Value> {
return :None;
}
-struct FuncKey {
+struct GloblKey {
name *const u8,
externp bool,
}
-struct FuncEntry {
+struct GloblEntry {
t enum {
Idk, Def, Decl
},
ty *const Type,
id int,
}
-static funcs Map<FuncKey, FuncEntry, struct {
- fn hash(e FuncKey) u32 {
+struct GloblKeyTraits {
+ fn hash(e GloblKey) u32 {
let h = fnv1a_s(FNV1A_INI, e.name);
h = fnv1a_i(h, as(int)e.externp);
return h;
}
- fn eq(a FuncKey, b FuncKey) bool {
+ fn eq(a GloblKey, b GloblKey) bool {
return streq(a.name, b.name) and a.externp == b.externp;
}
-}> = {};
+}
+static globls Map<GloblKey, GloblEntry, GloblKeyTraits> = {};
-extern fn llvm_addfn(decl *Decl) void {
+extern fn llvm_addglobl(decl *Decl, staticp bool) void {
assert(decl.toplevel, "llvm-addfn");
- let slot = funcs->get_slot({decl.name, decl.externp});
+ let slot = globls->get_slot({decl.name, decl.externp});
if slot.t != :Def {
slot.t = :Decl;
- slot.ty = decl.u.Fn.ty;
- slot.id = decl.u.Fn.id;
+ if staticp {
+ slot.ty = decl.u.Static.ty;
+ slot.id = decl.u.Static.id;
+ } else {
+ slot.ty = decl.u.Fn.ty;
+ slot.id = decl.u.Fn.id;
+ }
}
}
extern fn llvm_genfn(externp bool, name *const u8, f *Fn) void {
- funcs->put({name, externp}, {:Def, f.ty, f.id});
+ globls->put({name, externp}, {:Def, f.ty, f.id});
tmpid = 0;
gen("define%s %t ", externp ? "" : " internal", f.ty.u.Fn.ret);
if !externp {
@@ -822,32 +857,66 @@ extern fn llvm_genfn(externp bool, name *const u8, f *Fn) void {
gen("}\n");
}
+fn gendata(ty *const Type, ex *Expr) void {
+ fold(ex);
+ switch ex.u {
+ case IntLit i; return gen("%I", i.i);
+ case FloLit f; return gen("%f", f);
+ case BoolLit b; return gen("%d", b);
+ case NullLit; return gen("null");
+ case ZeroIni; return gen("zeroinitializer");
+ }
+ assert(#f, "bad static");
+}
+
+extern fn llvm_genstatic(externp bool, name *const u8, var *Var) void {
+ globls->put({name, externp}, {:Def, var.ty, var.id});
+ if !externp {
+ gen("@%s.%d", name, var.id);
+ } else {
+ gen("@%s", name);
+ }
+ let ini = var.ini->some_or({.u: :ZeroIni});
+ gen(" = %sglobal %t %C\n", externp ? "" : "internal ", var.ty, var.ty, &ini);
+}
+
extern fn llvm_fini() void {
vec_each(s, i, strs) {
gen("@.str.%z = internal constant [%z x i8] c%S;\n", i, s.#len + 1, s);
}
- map_each(f, k, funcs) {
- if f.t == :Decl {
- let ty = f.ty;
- gen("declare %t ", ty.u.Fn.ret);
+ map_each(g, k, globls) {
+ if g.t != :Decl {
+ continue;
+ }
+ let ty = g.ty;
+ switch ty.u {
+ case Fn f;
+ gen("declare %t ", f.ret);
if !k.externp {
- gen("@%s.%d(", k.name, f.id);
+ gen("@%s.%d(", k.name, g.id);
} else {
gen("@%s(", k.name);
}
- foreach(tyy, i, ty.u.Fn.params) {
+ foreach(tyy, i, f.params) {
gen("%t", tyy);
- if i < ty.u.Fn.params.#len - 1 {
+ if i < f.params.#len - 1 {
gen(", ");
- } else if ty.u.Fn.variadic {
+ } else if f.variadic {
gen(", ...");
}
}
gen(");\n");
+ case else
+ if !k.externp {
+ gen("@%s.%d", k.name, g.id);
+ } else {
+ gen("@%s", k.name);
+ }
+ gen(" = external global %t\n", ty);
}
}
strs->clear();
- funcs->clear();
+ globls->clear();
arena->destroy();
}
diff --git a/src/option.hff b/src/option.hff
index f0eddfc..7b935dc 100644
--- a/src/option.hff
+++ b/src/option.hff
@@ -5,4 +5,11 @@ enum union Option<T> {
fn empty(self Option) bool {
return self.#tag == :None;
}
+
+ fn some_or(self Option, it T) T {
+ switch self {
+ case None; return it;
+ case Some x; return x;
+ }
+ }
}
diff --git a/src/parse.cff b/src/parse.cff
index e731d47..5a50e96 100644
--- a/src/parse.cff
+++ b/src/parse.cff
@@ -2481,7 +2481,11 @@ fn parsevardecl(P *Parser, toplevel bool, externp bool, letp bool, yield DeclYie
decl.u.Static.id = id++;
decl.u.#tag = :Static;
}
- yield(putdecl(P, tok.loc, decl), yarg);
+ let decll *Decl #?;
+ yield(decll = putdecl(P, tok.loc, decl), yarg);
+ if !letp and !fwd {
+ llvm_genstatic(decl.externp, decl.name, &decl.u.Static);
+ }
if !lexmatch(P, &tok, ',') {
lexexpects(P, ';', "`,' or `;'");
@@ -2516,8 +2520,8 @@ fn parsefn(P *Parser, loc Loc, toplevel bool, externp bool, name *const u8) *Dec
if !lexmatch(P, #null, '{') {
lexexpects(P, ';', "';' or '{'");
- if toplevel {
- llvm_addfn(decl);
+ if toplevel or externp {
+ llvm_addglobl(decl, #f);
}
return decl;
}
@@ -2544,8 +2548,8 @@ fn parsefn(P *Parser, loc Loc, toplevel bool, externp bool, name *const u8) *Dec
(as(*Arena)P.alloc.a)->destroy();
}
}
- if toplevel {
- llvm_addfn(decl);
+ if toplevel or externp {
+ llvm_addglobl(decl, #f);
}
P.varid = varid;
P.loopid = loopid;
@@ -2855,8 +2859,11 @@ fn parsedecls(P *Parser, loc Loc, yield DeclYielder, yarg *void, toplevel bool)
a.yield(decl, a.yarg);
}
// ir_genstatic(a.P.irctx, decl);
+ if a.toplevel or a.externp {
+ llvm_addglobl(decl, #t);
+ }
}
- parsevardecl(P, toplevel, externp, #{let?} #t, &varyield, &Arg { P, externp, toplevel, yield, yarg });
+ parsevardecl(P, toplevel, externp, #{let?} #f, &varyield, &Arg { P, externp, toplevel, yield, yarg });
return;
case lexmatch(P, &tok, :kw_def);