aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cffc.hff2
-rw-r--r--src/llvm.cff71
-rw-r--r--src/parse.cff6
3 files changed, 66 insertions, 13 deletions
diff --git a/src/cffc.hff b/src/cffc.hff
index ca6ebea..d1d423f 100644
--- a/src/cffc.hff
+++ b/src/cffc.hff
@@ -241,7 +241,7 @@ struct Stmt {
Expr Expr,
Decl *Decl,
ISwitch struct { ex Expr, cs [#]ISwitchCase, f Block },
- EUSwitch struct { ex Expr, cs [#]EUSwitchCase, f Block },
+ EUSwitch struct { lvalue bool, ex Expr, cs [#]EUSwitchCase, f Block },
CSwitch struct { cs [#]CSwitchCase, f Block }
}
}
diff --git a/src/llvm.cff b/src/llvm.cff
index 9ad67a2..b0111fe 100644
--- a/src/llvm.cff
+++ b/src/llvm.cff
@@ -243,16 +243,17 @@ fn genaddr(f *Fn, ex *Expr) Value {
case :Struct;
gen("\t%v = getelementptr %t, %t %v, i32 0, i32 %d\n", addr, lhs.ty.u.Ptr, lhs.ty, lhs, idx);
case :Union;
- gen("\t%v = bitcast %t %v to %v", addr, lhs.ty, lhs, addr.ty);
+ gen("\t%v = bitcast %t %v to %t", addr, lhs.ty, lhs, addr.ty);
case else
- assert(#f, "nyi eunion access");
+ let off int = dot.fld.off;
+ gen("\t%v = getelementptr i8, %t %v, i32 %d\n", addr, lhs.ty, lhs, off);
}
return addr;
case EUTag eex;
let lhs = eex.ty->is(:Ptr) ? genexpr(f, eex) : genaddr(f, eex);
let addr = mktmp(mkptrtype(ex.ty));
- gen("\t%v = bitcast %t %v to %v", addr, lhs.ty, lhs, addr);
+ gen("\t%v = bitcast %t %v to %t", addr, lhs.ty, lhs, addr.ty);
return addr;
case AggIni ini;
@@ -906,24 +907,74 @@ fn genstmt(f *Fn, block *Block, st *Stmt) void {
gen("ISe%d: ", id);
nop();
+ case EUSwitch *sw;
+ static swid int = {};
+ let id = swid++;
+ let exaddr Value #?;
+ if sw.lvalue {
+ exaddr = genaddr(f, &sw.ex);
+ } else {
+ exaddr = mktmp(mkptrtype(sw.ex.ty));
+ gen("\t%v = alloca %t\n", exaddr, exaddr.ty);
+ let test = genexpr(f, &sw.ex);
+ gen("\tstore %t %v, %t %v\n", test.ty, test, exaddr.ty, exaddr);
+ }
+ let tag = (do
+ let addr = mktmp(mkptrtype(sw.ex.ty.u.Agg.enumty));
+ gen("\t%v = bitcast %t %v to %t\n", addr, exaddr.ty, exaddr, addr.ty);
+ let tmp = mktmp(sw.ex.ty.u.Agg.enumty);
+ gen("\t%v = load %t, %t %v\n", tmp, tmp.ty, addr.ty, addr);
+ tmp;
+ );
+ gen("\tswitch %t %v, label %%ESx%d [ ", tag.ty, tag, id);
+ foreach (c, i, sw.cs) {
+ let t = Value{tag.ty, :IImm(c.variant)};
+ gen(" %t %v, label %%ES%d.%d ", t.ty, t, id, i);
+ }
+ gen(" ]\n");
+ foreach (c, i, sw.cs) {
+ gen("ES%d.%d: ", id, i);
+ 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);
+ if c.captptr {
+ gen("\tstore %t %v, %t %%%s.%d\n", valaddr.ty, valaddr, mkptrtype(c.captty), c.capt, c.captid);
+ } else {
+ let val = mktmp(c.captty);
+ gen("\t%v = load %t, %t %v\n", val, val.ty, valaddr.ty, valaddr);
+ gen("\tstore %t %v, %t %%%s.%d\n", val.ty, val, mkptrtype(c.captty), c.capt, c.captid);
+ }
+ }
+ genblock(f, c.t);
+ gen("\tbr label %%ESe%d\n", id);
+ }
+ gen("ESx%d: ", id);
+ genblock(f, sw.f);
+ gen("\tbr label %%ESe%d\n", id);
+ gen("ESe%d: ", id);
+ nop();
+
case else
assert(#f, "stmt? %d", st.u.#tag);
}
}
fn genblock(f *Fn, block Block) Option<Value> {
- foreach_ptr (st, _, block.sts) {
- genstmt(f, &block, st);
+ let res Option<Value> = :None;
+ foreach_ptr (st, i, block.sts) {
+ if i == block.sts.#len - 1 and st.u.#tag == :Expr {
+ res = :Some(genexpr(f, &st.u.Expr));
+ } else {
+ genstmt(f, &block, st);
+ }
}
for let defers = block.defers; defers; defers = defers.next {
if defers.blockid == block.id {
- let ex = genexpr(f, &defers.ex);
- if defers.next == #null {
- return :Some(ex);
- }
+ genexpr(f, &defers.ex);
}
}
- return :None;
+ return res;
}
struct GloblKey {
diff --git a/src/parse.cff b/src/parse.cff
index 2611906..2ac15ba 100644
--- a/src/parse.cff
+++ b/src/parse.cff
@@ -2272,8 +2272,9 @@ fn psteuswitch(P *Parser, loc Loc, test Expr) Stmt {
ty = mkptrtype(test.ty.konst ? constify(ty) : ty);
}
pushenv(P, env);
+ c.captid = P.varid++;
putdecl(P, tok.loc, {
- c.capt, tok.loc, .u: :Let { c.captty = ty, :None, #f, P.curfn.id, P.varid++ }
+ c.capt, tok.loc, .u: :Let { c.captty = ty, :None, #f, P.curfn.id, c.captid }
});
}
lexexpect(P, ';');
@@ -2281,10 +2282,11 @@ fn psteuswitch(P *Parser, loc Loc, test Expr) Stmt {
if c.capt {
popenv(P);
}
+ cs->push(c);
}
- return { loc, :EUSwitch { test, cs->move(P.alloc), f }};
+ return { loc, :EUSwitch { islvalue(test), test, cs->move(P.alloc), f }};
}
fn pstcswitch(P *Parser, loc Loc) Stmt {