aboutsummaryrefslogtreecommitdiff
path: root/src/llvm.cff
diff options
context:
space:
mode:
Diffstat (limited to 'src/llvm.cff')
-rw-r--r--src/llvm.cff117
1 files changed, 93 insertions, 24 deletions
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();
}