From 9f320002800b0a8b7601528334f97ba64182bdd6 Mon Sep 17 00:00:00 2001 From: lemon Date: Wed, 24 Aug 2022 14:46:36 +0200 Subject: more llvm --- src/cffc.hff | 3 +- src/llvm.cff | 117 +++++++++++++++++++++++++++++++++++++++++++++------------ src/option.hff | 7 ++++ src/parse.cff | 19 +++++++--- 4 files changed, 115 insertions(+), 31 deletions(-) (limited to 'src') 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 { 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 = {}; +} +static globls Map = {}; -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 { 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); -- cgit v1.2.3