From af617f24c5f2f2cab357ace9d822c6948c7e487f Mon Sep 17 00:00:00 2001 From: lemon Date: Wed, 31 Aug 2022 11:23:14 +0200 Subject: get close to self hosting (ack works) --- Makefile | 2 +- bootstrap/cgen.c | 2 ++ src/cffc.hff | 8 +++--- src/llvm.cff | 76 ++++++++++++++++++++++++++++++++------------------------ src/parse.cff | 19 +++++++++++--- 5 files changed, 67 insertions(+), 40 deletions(-) diff --git a/Makefile b/Makefile index 0ac38e4..d6551b3 100644 --- a/Makefile +++ b/Makefile @@ -37,6 +37,6 @@ build/%.o: %.cff @echo -e '\e[1mCFFC\e[0m' '\e[32m'"$<"'\e[0m' '->' '\e[34m'"$@"'\e[0m' $V$(CFFC) $< -o $@.ll $Vset -euo pipefail;\ - (opt -O0 -opaque-pointers $@.ll | llc --relocation-model=dynamic-no-pic -opaque-pointers | as - -o $@) || ($(RM) $@; false) + (opt -Oz -opaque-pointers $@.ll | llc --relocation-model=dynamic-no-pic -opaque-pointers | as - -o $@) || ($(RM) $@; false) diff --git a/bootstrap/cgen.c b/bootstrap/cgen.c index 7db84ea..ee88280 100644 --- a/bootstrap/cgen.c +++ b/bootstrap/cgen.c @@ -54,6 +54,8 @@ pristring(const char *s, u64 n) { pri("\\\""); else if (s[i] == '\\') pri("\\\\"); + else if (s[i] == '?') + pri("\\?"); else if (isprint(s[i])) pri("%c", s[i]); else diff --git a/src/cffc.hff b/src/cffc.hff index 4d57d3d..d6de469 100644 --- a/src/cffc.hff +++ b/src/cffc.hff @@ -467,10 +467,12 @@ fn mkarrtype(len i64, konst bool, child *const Type) *const Type { }); } fn mkptrtype(child *const Type) *const Type { - return interntype(&Type { + let tmp typeof((Type{}).u) = :Ptr(child); + let ty = Type { g_targ.ptrsize, - .u: :Ptr(child) - }); + .u: tmp + }; + return interntype(&ty); } extern fn mkslicetype(child *const Type) *const Type; diff --git a/src/llvm.cff b/src/llvm.cff index bb6af3f..b0b1027 100644 --- a/src/llvm.cff +++ b/src/llvm.cff @@ -23,7 +23,8 @@ struct Value { } } -fn gen(fmt *const u8, ...) void; +// XXX if gen isn't extern llvm hates it and wooshes it away ? +extern fn gen(fmt *const u8, ...) void; extern fn genagg(ty *const Type) void { let agg = &ty.u.Agg; if agg.fwd { @@ -42,29 +43,39 @@ extern fn genagg(ty *const Type) void { } else if agg.kind == :Union { let size = ty.size; let ty *const Type = #null; - foreach (fld, i, agg.flds) { - if ty == #null or fld.ty.align > ty.align { - ty = fld.ty; + do { + foreach (fld, i, agg.flds) { + if ty == #null or fld.ty.align > ty.align or fld.ty.size > ty.size { + ty = fld.ty; + } } + } while ty->is(:Agg) and ty.u.Agg.kind != :Struct; + if ty->is(:Agg) { + // struct + gen("{ i%z, [%z x i8] }", ty.align * 8, size - ty.align); + } else { + gen("{ %t, [%z x i8] }", ty, size - ty.size); } - gen("{ %t ", ty); - if ty.size < size { - gen(", [%z x i8] ", size - ty.size); - } - gen("}"); } else if agg.kind == :EUnion { - gen("{ %t, ", agg.enumty); let size = ty.size; + gen("{ %t, [%z x i8],", agg.enumty, ty.align - agg.enumty.size); let ty *const Type = #null; let off isize #?; - foreach (fld, i, agg.flds) { - if ty == #null or (fld.ty != #null and fld.ty.align > ty.align) { - ty = fld.ty; - off = fld.off; + do { + foreach (fld, i, agg.flds) { + if ty == #null or (fld.ty != #null and (fld.ty.align > ty.align or fld.ty.size > ty.size)) { + ty = fld.ty; + off = fld.off; + } } - } + } while ty->is(:Agg) and ty.u.Agg.kind != :Struct; ty = ty ?? ty_void; - gen(" %t, [%z x i8] }", ty, size - ty.size - off); + if ty->is(:Agg) { + // struct + gen(" i%z, [%z x i8] }", ty.align * 8, size - off - ty.align); + } else { + gen(" %t, [%z x i8] }", ty, size - ty.size - off); + } } } @@ -77,7 +88,7 @@ extern fn llvm_addtype(ty *const Type) void { } fn gendata(ty *const Type, ex *Expr) void; -fn gen(fmt *const u8, ...) void { +extern fn gen(fmt *const u8, ...) void { let ap va_list #?; ap->start(fmt); @@ -297,9 +308,9 @@ fn genref(f *Fn, ex *Expr) Ref { lhs.ty.u.Ptr, lhs.ty, &lhs, idx); case :Union; addr = gentmp(ptrty, "bitcast %t %v to %t", lhs.ty, &lhs, ptrty); - case else + case :EUnion; let off int = dot.fld.off; - addr = gentmp(ptrty, "getelementptr i8, %t %v, i32 %d", lhs.ty, &lhs, off); + addr = gentmp(ptrty, "getelementptr i8, ptr %v, i32 %d", &lhs, off); } return :Addr(addr); @@ -326,9 +337,10 @@ fn genref(f *Fn, ex *Expr) Ref { gen("\t%v = getelementptr %t, %t %v, i32 0, i32 %d\n", &ptr, ex.ty, tmp.ty, &tmp, idx); case :Union; gen("\t%v = bitcast %t %v to %t\n", &ptr, tmp.ty, &tmp, ptr.ty); + case else assert(#f, "?"); } let it = convert(f, fld.ty, fex); - gen("\tstore %t %v, %t %v\n", fld.ty, &it, ptr.ty, &ptr); + gen("\tstore %t %v, ptr %v\n", fld.ty, &it, &ptr); } return :Addr(tmp); @@ -444,6 +456,12 @@ fn convert(f *Fn, to *const Type, ex *Expr) Value { case to->is(:Flo) and from->is(:Int); return cvt(from.u.Int.sgn ? "sitofp" : "uitofp"); + + case to->is(:Ptr) and from->is(:Int); + return cvt("inttoptr"); + + case to->is(:Int) and from->is(:Ptr); + return cvt("ptrtoint"); case to->is(:Int) and from->is(:Flo) and to.size < ty_int.size; let t0 = mktmp(ty_int); @@ -958,15 +976,12 @@ fn genexpr(f *Fn, ex *Expr) Value { let t0 = mktmp(mkptrtype(ex.ty)); let vidx = ini.var - ex.ty.u.Agg.flds.#ptr; gen("\t%v = alloca %t\n", &t0, ex.ty); - gen("\tstore %t zeroinitializer, %t %v\n", ex.ty, t0.ty, &t0); - gen("\tstore %t %d, %t %v\n", ex.ty.u.Agg.enumty.u.Enum.intty, vidx, t0.ty, &t0); + gen("\tstore %t zeroinitializer, ptr %v\n", ex.ty, &t0); + gen("\tstore %t %d, ptr %v\n", ex.ty.u.Agg.enumty, vidx, &t0); if ini.var.ty != #null { let tini = convert(f, ini.var.ty, ini.ex); - let t1 = mktmp(mkptrtype(ini.var.ty)); - gen("\t%v = bitcast %t %v to %t\n", &t1, t0.ty, &t0, t1.ty); - let t2 = mktmp(t1.ty); - gen("\t%v = getelementptr %t, %t %v, i32 1\n", &t2, ini.var.ty, t1.ty, &t1); - gen("\tstore %t %v, %t %v\n", tini.ty, &tini, t2.ty, &t2); + let t2 = gentmp(t0.ty, "getelementptr i8, ptr %v, i32 %z", &t0, ini.var.off); + gen("\tstore %t %v, ptr %v\n", tini.ty, &tini, &t2); } let res = mktmp(ex.ty); gen("\t%v = load %t, %t %v\n", &res, res.ty, t0.ty, &t0); @@ -975,7 +990,6 @@ fn genexpr(f *Fn, ex *Expr) Value { case VaStart ap; let ap = genref(f, ap).Addr; gen("\tcall void @llvm.va_start(ptr %v)\n", &ap); - return nop(); case VaArg ap; let ap = genref(f, ap).Addr; @@ -984,7 +998,6 @@ fn genexpr(f *Fn, ex *Expr) Value { case VaEnd ap; let ap = genref(f, ap).Addr; gen("\tcall void @llvm.va_end(ptr %v)\n", &ap); - return nop(); case Stmt block; switch genblock(f, block) { @@ -1151,7 +1164,7 @@ fn genstmt(f *Fn, block *Block, st *Stmt) void { exaddr = genref(f, &sw.ex).Addr; } else { exaddr = mktmp(mkptrtype(sw.ex.ty)); - gen("\t%v = alloca %t\n", &exaddr, exaddr.ty); + gen("\t%v = alloca %t\n", &exaddr, sw.ex.ty); let test = genexpr(f, &sw.ex); gen("\tstore %t %v, %t %v\n", test.ty, &test, exaddr.ty, &exaddr); } @@ -1173,8 +1186,7 @@ fn genstmt(f *Fn, block *Block, st *Stmt) void { if c.capt { gen("\t%%%s.%d = alloca %t\n", c.capt, c.captid, c.captty); let valaddr = mktmp(mkptrtype(c.fld.ty)); - gen("\t%v = getelementptr i8, %t %v, i32 %d\n", &valaddr, exaddr.ty, &exaddr, - as(int)c.fld.off); + gen("\t%v = getelementptr i8, ptr %v, i32 %z\n", &valaddr, &exaddr, c.fld.off); if c.captptr { gen("\tstore %t %v, %t %%%s.%d\n", valaddr.ty, &valaddr, mkptrtype(c.captty), c.capt, c.captid); } else { diff --git a/src/parse.cff b/src/parse.cff index bd5262e..7249390 100644 --- a/src/parse.cff +++ b/src/parse.cff @@ -561,7 +561,8 @@ fn lex(P *Parser) Tok { fn lexpeek(P *Parser) Tok { switch P.peektok { - case Some t; return t; + case Some t; + return t; } let tok = lex(P); P.peektok = :Some(tok); @@ -2763,6 +2764,8 @@ fn parsevardecl(P *Parser, toplevel bool, externp bool, letp bool, yield DeclYie } while !lexmatch(P, &tok, ';'); } + extern fn BREAK() void {} + fn parsefn(P *Parser, loc Loc, toplevel bool, externp bool, name *const u8) *Decl { let decl Decl = { name, @@ -2784,6 +2787,11 @@ fn parsefn(P *Parser, loc Loc, toplevel bool, externp bool, name *const u8) *Dec static id int = 0; Fn.id = ++id; // TODO tlalloc necessary for templates. but it leaks some memory + let d Decl #?; + extern fn memset(*void, int, usize) *void; + memset(&d, 0, sizeof(d)); + d = decl; + let decl = putdecl_alloc(P, P.tlalloc, loc, decl); let Fn = &decl.u.Fn; decl.toplevel = toplevel; @@ -3040,6 +3048,12 @@ fn parsedecls(P *Parser, loc Loc, yield DeclYielder, yarg *void, toplevel bool) externp = #f, name *const u8 = #null; + + if lexmatch(P, &tok, ';') or lexmatch(P, &tok, :eof) { + // no-op + return; + } + let attr u32 = 0; if lexmatch(P, &tok, '#') { lexexpect(P, '['); @@ -3062,9 +3076,6 @@ fn parsedecls(P *Parser, loc Loc, yield DeclYielder, yarg *void, toplevel bool) switch { - case lexmatch(P, &tok, ';') or lexmatch(P, &tok, :eof); - // no-op - case lexmatch(P, &tok, :kw_fn); let name = lexmatch(P, &tok, :ident) ? tok.u.ident : #null; decl = parsefn(P, tok.loc, toplevel, externp, name); -- cgit v1.2.3