aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/llvm.cff223
-rw-r--r--src/parse.cff13
-rw-r--r--test/2.cff4
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");
}
diff --git a/test/2.cff b/test/2.cff
index 8b512ea..9069d24 100644
--- a/test/2.cff
+++ b/test/2.cff
@@ -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);
}