diff options
| -rw-r--r-- | src/llvm.cff | 223 | ||||
| -rw-r--r-- | src/parse.cff | 13 | ||||
| -rw-r--r-- | test/2.cff | 4 |
3 files changed, 120 insertions, 120 deletions
diff --git a/src/llvm.cff b/src/llvm.cff index 32b1066..200805d 100644 --- a/src/llvm.cff +++ b/src/llvm.cff @@ -219,33 +219,38 @@ static arena Arena = {}; static alloc Allocator = {}; static strs Vec<[#]const u8> = {}; -fn genaddr(f *Fn, ex *Expr) Value { +enum union Ref { + Addr Value, + BitDot struct { lhs Value, fld *const BitFField } +} + +fn genref(f *Fn, ex *Expr) Ref { switch ex.u { case StrLit s; let p *u8 = alloc->alloc(s.#len + 1, 1); memcpy(p, s.#ptr, s.#len + 1); let s = p[0::s.#len]; strs->push(s); - return {mkptrtype(ex.ty), :StrConstRef(strs.len - 1)}; + return :Addr{mkptrtype(ex.ty), :StrConstRef(strs.len - 1)}; case Symbol decl; switch decl.u { - case Let *var; return {mkptrtype(var.ty), :LocalRef(var)}; - case Static *var; return {mkptrtype(var.ty), :GlobalRef(var)}; - case Fn *f; return {mkptrtype(f.ty), :FnRef(f)}; + case Let *var; return :Addr{mkptrtype(var.ty), :LocalRef(var)}; + case Static *var; return :Addr{mkptrtype(var.ty), :GlobalRef(var)}; + case Fn *f; return :Addr{mkptrtype(f.ty), :FnRef(f)}; } case UnOp un; switch un.op { case :deref; - return genexpr(f, un.ex); + return genref(f, un.ex); case :addrof; - return genaddr(f, un.ex); + return genref(f, un.ex); } case Index idx; let lhs Value #?; switch idx.lhs.ty.u { case Arr arrty; - let arr = genaddr(f, idx.lhs); + let arr = genref(f, idx.lhs).Addr; lhs = gentmp(mkptrtype(ex.ty), "getelementptr %t, %t %v, i32 0, i32 0", idx.lhs.ty, arr.ty, arr); case Ptr; lhs = genexpr(f, idx.lhs); @@ -258,10 +263,10 @@ fn genaddr(f *Fn, ex *Expr) Value { let rhs = genexpr(f, idx.rhs); let addr = gentmp(mkptrtype(ex.ty), "getelementptr %t, %t %v, %t %v", ex.ty, lhs.ty, lhs, rhs.ty, rhs); - return addr; + return :Addr(addr); case Dot dot; - let lhs = dot.lhs.ty->is(:Ptr) ? genexpr(f, dot.lhs) : genaddr(f, dot.lhs); + let lhs = dot.lhs.ty->is(:Ptr) ? genexpr(f, dot.lhs) : genref(f, dot.lhs).Addr; assert(dot.fld.ty.align > 0, "%s align %zu", dot.fld.name, dot.fld.ty.align); assert(dot.fld.off % dot.fld.ty.align == 0, "field align %s %zu %zu", dot.fld.name, dot.fld.off, dot.fld.ty.align); @@ -283,15 +288,18 @@ fn genaddr(f *Fn, ex *Expr) Value { let off int = dot.fld.off; addr = gentmp(ptrty, "getelementptr i8, %t %v, i32 %d", lhs.ty, lhs, off); } - return addr; + return :Addr(addr); + + case BitDot dot; + return :BitDot{genref(f, dot.lhs).Addr, dot.fld}; case EUTag eex; - let lhs = eex.ty->is(:Ptr) ? genexpr(f, eex) : genaddr(f, eex); + let lhs = eex.ty->is(:Ptr) ? genexpr(f, eex) : genref(f, eex).Addr; let addr = gentmp(mkptrtype(ex.ty), "bitcast %t %v to %t", lhs.ty, lhs, mkptrtype(ex.ty)); - return addr; + return :Addr(addr); case BitRaw ex; - return genaddr(f, ex); + return genref(f, ex); case AggIni ini; let tmp = gentmp(mkptrtype(ex.ty), "alloca %t", ex.ty); @@ -308,7 +316,7 @@ fn genaddr(f *Fn, ex *Expr) Value { } gen("\tstore %t %v, %t %v\n", fld.ty, convert(f, fld.ty, fex), ptr.ty, ptr); } - return tmp; + return :Addr(tmp); case ArrIni ini; let ty = mkarrtype(ini.maxn, #f, ex.ty.u.Arr.child); @@ -320,9 +328,56 @@ fn genaddr(f *Fn, ex *Expr) Value { gen("\t%v = getelementptr %t, %t %v, i32 0, i32 %d\n", ptr, ty, tmp.ty, tmp, idx); gen("\tstore %t %v, %t %v\n", fex.ty, convert(f, ty.u.Arr.child, fex), ptr.ty, ptr); } - return tmp; + return :Addr(tmp); + } + assert(#f, "genref %d", ex.u.#tag); +} + +fn genload(f *Fn, ref Ref) Value { + switch ref { + case Addr addr; + return gentmp(addr.ty.u.Ptr, "load %t, %t %v", addr.ty.u.Ptr, addr.ty, addr); + + case BitDot dot; + let intty = dot.lhs.ty.u.BitF.intty; + let fld = dot.fld; + let lhs = genload(f, :Addr(dot.lhs)); + let shifted = fld.off == 0 ? lhs : gentmp(lhs.ty, "lshr %t %v, %d", lhs.ty, lhs, fld.off); + let truncd = gentmp(#null, "trunc %t %v to i%d", shifted.ty, shifted, fld.size); + let res = mktmp(fld.ty); + switch { + case dot.fld.ty->is(:Bool); + let tmp = gentmp(ty_bool, "icmp ne i%d %v, 0", fld.size, truncd); + gen("\t%v = zext i1 %v to %t\n", res, tmp, res.ty); + case dot.fld.ty->is(:Int); + gen("\t%v = %s i%d %v to %t\n", res, + dot.fld.ty.u.Int.sgn ? "sext" : "zext", truncd, fld.size, lhs.ty); + case else assert(#f, ""); + } + return res; + } +} + +fn genstore(f *Fn, ref Ref, v Value) void { + switch ref { + case Addr addr; + gen("\tstore %t %v, %t %v\n", v.ty, v, addr.ty, addr); + + case BitDot dot; + let intty = dot.lhs.ty.u.BitF.intty; + let fld = dot.fld; + let srcmask = fld.size == 64 ? ~0u64 : ((1u64 << fld.size) - 1); + let addr = dot.lhs; + let src0 = v; + let src = gentmp(intty, "and %t %v, %I", intty, src0, srcmask); + let src = gentmp(intty, "shl %t %v, %d", src.ty, src, fld.off); + let dstmask = ~(srcmask << fld.off); + let lhs = gentmp(intty, "load %t, %t %v", intty, addr.ty, addr); + let lhs = genload(f, :Addr(addr)); + let lhs = gentmp(lhs.ty, "and %t %v, %I", lhs.ty, lhs, dstmask); + let raw = gentmp(lhs.ty, "or %t %v, %v", lhs.ty, lhs, src); + gen("\tstore %t %v, %t %v\n", raw.ty, raw, addr.ty, addr); } - assert(#f, "genaddr %d", ex.u.#tag); } fn convert(f *Fn, to *const Type, ex *Expr) Value { @@ -405,7 +460,7 @@ fn convert(f *Fn, to *const Type, ex *Expr) Value { return t; case to->is(:Ptr) and from->is(:Arr); - let addr = genaddr(f, ex); + let addr = genref(f, ex).Addr; let t = mktmp(ex.ty); gen("\t%v = getelementptr %t, %t %v, %t 0, %t 0\n", t, addr.ty.u.Ptr, addr.ty, addr, ty_usize, ty_usize); @@ -495,17 +550,12 @@ fn genexpr(f *Fn, ex *Expr) Value { ] defmacro genassignop(inst, type, a, b) [ (do - let addr = genaddr(f, a); + let ref = genref(f, a); let rhs = convert(f, a.ty, b); - let lhs0 = mktmp(type); - gen("\t%v = load %t, %t %v\n", lhs0, type, addr.ty, addr); - let tmp = (do - let t = mktmp(ex.ty); - gen("\t%v = %s %t %v, %v\n", t, inst, ex.ty, lhs0, rhs); - t; - ); - gen("\tstore %t %v, %t %v\n", tmp.ty, tmp, addr.ty, addr); - rhs; + let lhs0 = genload(f, ref); + let tmp = gentmp(ex.ty, "%s %t %v, %v", inst, ex.ty, lhs0, rhs); + genstore(f, ref, tmp); + tmp; ) ] switch b.op { @@ -535,45 +585,27 @@ fn genexpr(f *Fn, ex *Expr) Value { case '>'; gencmp(ty2->is(:Flo) ? "ogt" : ty2.u.Int.sgn ? "sgt" : "ugt"); case '>='; gencmp(ty2->is(:Flo) ? "oge" : ty2.u.Int.sgn ? "sge" : "uge"); case '='; - if b.lhs.u.#tag != :BitDot { - let addr = genaddr(f, b.lhs); - let rhs = convert(f, b.lhs.ty, b.rhs); - gen("\tstore %t %v, %t %v\n", ex.ty, rhs, addr.ty, addr); - return rhs; - } else { - let dot = &b.lhs.u.BitDot; - let intty = dot.lhs.ty.u.BitF.intty; - let fld = dot.fld; - let srcmask = fld.size == 64 ? ~0u64 : ((1u64 << fld.size) - 1); - let addr = genaddr(f, dot.lhs); - let src0 = convert(f, intty, b.rhs); - let src = gentmp(intty, "and %t %v, %I", src0.ty, src0, srcmask); - let src = gentmp(intty, "shl %t %v, %d", src.ty, src, fld.off); - let dstmask = ~(srcmask << fld.off); - let lhs = gentmp(intty, "load %t, %t %v", intty, addr.ty, addr); - let lhs = gentmp(lhs.ty, "and %t %v, %I", lhs.ty, lhs, dstmask); - let raw = gentmp(lhs.ty, "or %t %v, %v", lhs.ty, lhs, src); - gen("\tstore %t %v, %t %v\n", raw.ty, raw, addr.ty, addr); - let res = gentmp(intty, "load %t, %t %v", fld.ty, addr.ty, addr); - return res; - } + let ref = genref(f, b.lhs); + let rhs = convert(f, b.lhs.ty, b.rhs); + genstore(f, ref, rhs); + return rhs; + case '+='; - let addr = genaddr(f, b.lhs); + let ref = genref(f, b.lhs); let rhs = convert(f, b.lhs.ty, b.rhs); - let lhs0 = mktmp(ex.ty); - gen("\t%v = load %t, %t %v\n", lhs0, ex.ty, addr.ty, addr); + let lhs0 = genload(f, ref); let tmp = genadd(ex.ty, lhs0, rhs); - gen("\tstore %t %v, %t %v\n", tmp.ty, tmp, addr.ty, addr); - return rhs; + genstore(f, ref, tmp); + return tmp; case '-='; - let addr = genaddr(f, b.lhs); + let ref = genref(f, b.lhs); let rhs = convert(f, b.lhs.ty, b.rhs); - let lhs0 = mktmp(ex.ty); - gen("\t%v = load %t, %t %v\n", lhs0, ex.ty, addr.ty, addr); + let lhs0 = genload(f, ref); let tmp = gensub(ex.ty, lhs0, rhs); - gen("\tstore %t %v, %t %v\n", tmp.ty, tmp, addr.ty, addr); - return rhs; + genstore(f, ref, tmp); + return tmp; + case '*='; return genassignop(ex.ty->is(:Flo) ? "fdiv" : "mul", ex.ty, b.lhs, b.rhs); case '/='; @@ -674,30 +706,28 @@ fn genexpr(f *Fn, ex *Expr) Value { case :preinc, :predec; let one = Value{ex.ty, :IImm(un.op == :preinc ? 1 : -1)}; - let addr = genaddr(f, un.ex); - let var = mktmp(ex.ty); + let ref = genref(f, un.ex); let val = mktmp(ex.ty); - gen("\t%v = load %t, %t %v\n", var, ex.ty, addr.ty, addr); + let var = genload(f, ref); if ex.ty->is(:Ptr) { gen("\t%v = getelementptr %t, %t %v, i32 %v\n", val, ex.ty.u.Ptr, ex.ty, var, one); } else { gen("\t%v = add %t %v, %v\n", val, ex.ty, var, one); } - gen("\tstore %t %v, %t %v\n", ex.ty, val, addr.ty, addr); + genstore(f, ref, val); return val; case :postinc, :postdec; let one = Value{ex.ty, :IImm(un.op == :postinc ? 1 : -1)}; - let addr = genaddr(f, un.ex); - let var = mktmp(ex.ty); + let ref = genref(f, un.ex); let val = mktmp(ex.ty); - gen("\t%v = load %t, %t %v\n", var, ex.ty, addr.ty, addr); + let var = genload(f, ref); if ex.ty->is(:Ptr) { gen("\t%v = getelementptr %t, %t %v, i32 %v\n", val, ex.ty.u.Ptr, ex.ty, var, one); } else { gen("\t%v = add %t %v, %v\n", val, ex.ty, var, one); } - gen("\tstore %t %v, %t %v\n", ex.ty, val, addr.ty, addr); + genstore(f, ref, val); return var; case :deref; @@ -707,44 +737,26 @@ fn genexpr(f *Fn, ex *Expr) Value { return val; case :addrof; - return genaddr(f, ex); + return genref(f, ex).Addr; case else assert(#f, "unop?"); } case Index; - let tmp = mktmp(ex.ty); - let addr = genaddr(f, ex); - gen("\t%v = load %t, %t %v\n", tmp, ex.ty, addr.ty, addr); - return tmp; + let ref = genref(f, ex); + return genload(f, ref); case Dot; - let tmp = mktmp(ex.ty); - let addr = genaddr(f, ex); - gen("\t%v = load %t, %t %v\n", tmp, ex.ty, addr.ty, addr); - return tmp; + let ref = genref(f, ex); + return genload(f, ref); case BitRaw ex; return genexpr(f, ex); case BitDot dot; - let fld = dot.fld; - let lhs = genexpr(f, dot.lhs); - let shifted = fld.off == 0 ? lhs : gentmp(lhs.ty, "lshr %t %v, %d", lhs.ty, lhs, fld.off); - let truncd = gentmp(#null, "trunc %t %v to i%d", shifted.ty, shifted, fld.size); - let res = mktmp(fld.ty); - switch { - case dot.fld.ty->is(:Bool); - let tmp = gentmp(ty_bool, "icmp ne i%d %v, 0", fld.size, truncd); - gen("\t%v = zext i1 %v to %t\n", res, tmp, res.ty); - - case dot.fld.ty->is(:Int); - gen("\t%v = %s i%d %v to %t\n", res, dot.fld.ty.u.Int.sgn ? "sext" : "zext", truncd, fld.size, lhs.ty); - - case else assert(#f, ""); - } - return res; + let ref = genref(f, ex); + return genload(f, ref); case SPtr sl; let sl = genexpr(f, sl); @@ -759,11 +771,8 @@ fn genexpr(f *Fn, ex *Expr) Value { return len; case EUTag; - let tmp = mktmp(ex.ty); - let addr = genaddr(f, ex); - gen("\t%v = load %t, %t %v\n", tmp, ex.ty, addr.ty, addr); - return tmp; - + let ref = genref(f, ex); + return genload(f, ref); case Cast it; return convert(f, ex.ty, it); @@ -773,15 +782,13 @@ fn genexpr(f *Fn, ex *Expr) Value { case Fn *f; return {ex.ty, :Fn(f)}; case else - let tmp = mktmp(ex.ty); - let addr = genaddr(f, ex); - gen("\t%v = load %t, %t %v\n", tmp, ex.ty, addr.ty, addr); - return tmp; + let ref = genref(f, ex); + return genload(f, ref); } case Slice sl; if sl.lhs.ty.u.#tag == :Arr { - let addr = genaddr(f, sl.lhs); + let addr = genref(f, sl.lhs).Addr; let begin = convert(f, ty_usize, sl.begin); let end = convert(f, ty_usize, sl.end); let len = mktmp(ty_usize); @@ -860,14 +867,12 @@ fn genexpr(f *Fn, ex *Expr) Value { return t; case AggIni ini; - let tmp = genaddr(f, ex); - let val = mktmp(ex.ty); - gen("\t%v = load %t, %t %v\n", val, ex.ty, tmp.ty, tmp); - return val; + let ref = genref(f, ex); + return genload(f, ref); case ArrIni ini; let ty = mkarrtype(ini.maxn, #f, ex.ty.u.Arr.child); - let tmp = genaddr(f, ex); + let tmp = genref(f, ex).Addr; let val = mktmp(ty); gen("\t%v = load %t, %t %v\n", val, ty, tmp.ty, tmp); return val; @@ -1045,7 +1050,7 @@ fn genstmt(f *Fn, block *Block, st *Stmt) void { let id = swid++; let exaddr Value #?; if sw.lvalue { - exaddr = genaddr(f, &sw.ex); + exaddr = genref(f, &sw.ex).Addr; } else { exaddr = mktmp(mkptrtype(sw.ex.ty)); gen("\t%v = alloca %t\n", exaddr, exaddr.ty); diff --git a/src/parse.cff b/src/parse.cff index 364b23b..b978f4b 100644 --- a/src/parse.cff +++ b/src/parse.cff @@ -1676,10 +1676,6 @@ fn pexpostfix(P *Parser) Expr { if ex.ty.konst { err(P, ex.loc, "left operand to prefix %qT operator is const", tok); } - if ex.u.#tag == :BitDot { - err(P, ex.loc, "cannot apply post-%srement operator to bitfield value", - tok.t == '++' ? "inc" : "dec"); - } ex = { tok.loc, ex.ty, .u: :UnOp { tok.t == '++' ? :postinc : :postdec, exprdup(P.alloc, ex) @@ -1882,10 +1878,6 @@ fn pexprefix(P *Parser) Expr { if ex.ty.konst { err(P, ex.loc, "left operand to prefix %qT operator is const", tok); } - if ex.u.#tag == :BitDot { - err(P, ex.loc, "cannot apply pre-%srement operator to bitfield value", - tok.t == '++' ? "inc" : "dec"); - } return { tok.loc, ex.ty, .u: :UnOp { tok.t == '++' ? :preinc : :predec, exprdup(P.alloc, ex) @@ -1916,6 +1908,9 @@ fn pexprefix(P *Parser) Expr { and !(ex.u.#tag == :ZeroIni or ex.u.#tag == :AggIni or ex.u.#tag == :ArrIni) { err(P, ex.loc, "invalid operand to `&': not an lvalue"); } + if ex.u.#tag == :BitDot { + err(P, ex.loc, "cannot take address of bitfield value"); + } return { tok.loc, ty2, .u: :UnOp { :addrof, exprdup(P.alloc, ex) }}; case lexmatch(P, &tok, :kw_as); @@ -2142,8 +2137,6 @@ fn pexassign(P *Parser) Expr { err(P, ex.loc, "operands %t and %t to assignment operator %qT have incompatible types", ex.ty, rhs.ty, tok); - case okind != :Set and ex.u.#tag == :BitDot; - err(P, ex.loc, "cannot apply compound assignment operator to bitfield value"); case ex.ty.konst; err(P, ex.loc, "left operand to assignment is const"); } @@ -10,8 +10,10 @@ extern fn main() int { let foo Foo = {}; printf("0x%X: %d, %d, %d\n", foo.#raw, foo.tag, foo.flag, foo.num); foo.tag = 3; - foo.#raw += 1; + printf("%d\n", foo.#raw += 1); + --foo.tag; foo.flag = #t; foo.num = -2; + foo.num *= 10; printf("0x%X: %d, %d, %d\n", foo.#raw, foo.tag, foo.flag, foo.num); } |