aboutsummaryrefslogtreecommitdiff
path: root/src/comp
diff options
context:
space:
mode:
authorGraydon Hoare <[email protected]>2010-10-04 15:55:12 -0700
committerGraydon Hoare <[email protected]>2010-10-04 15:55:12 -0700
commit44e4b2d63aef1e6cb572acfa327ea2c3a36083e8 (patch)
treed48f06f491e20d4f176c7e1435ba953ec549d72c /src/comp
parentSupport refcount-drop and conditional free in rustc. (diff)
downloadrust-44e4b2d63aef1e6cb572acfa327ea2c3a36083e8.tar.xz
rust-44e4b2d63aef1e6cb572acfa327ea2c3a36083e8.zip
Teach rustc about phi nodes, block relationships. Translate if- and block-expressions.
Diffstat (limited to 'src/comp')
-rw-r--r--src/comp/front/ast.rs9
-rw-r--r--src/comp/front/parser.rs60
-rw-r--r--src/comp/lib/llvm.rs10
-rw-r--r--src/comp/middle/trans.rs349
-rw-r--r--src/comp/util/common.rs8
5 files changed, 324 insertions, 112 deletions
diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs
index c74e1620..48ba9187 100644
--- a/src/comp/front/ast.rs
+++ b/src/comp/front/ast.rs
@@ -1,7 +1,10 @@
-import std.util.option;
+import util.common.option;
import std.map.hashmap;
import util.common.span;
+import util.common.option;
+import util.common.some;
+import util.common.none;
type ident = str;
@@ -40,10 +43,10 @@ tag unop {
}
tag stmt {
- stmt_block(block);
stmt_decl(@decl);
stmt_ret(option[@expr]);
stmt_log(@expr);
+ stmt_expr(@expr);
}
tag decl {
@@ -63,6 +66,8 @@ tag expr {
expr_field(@expr, ident);
expr_index(@expr, @expr);
expr_cast(@expr, ty);
+ expr_if(@expr, block, option[block]);
+ expr_block(block);
}
tag lit {
diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs
index 44bddf08..12a1f072 100644
--- a/src/comp/front/parser.rs
+++ b/src/comp/front/parser.rs
@@ -2,15 +2,9 @@ import std._io;
import driver.session;
import util.common;
import util.common.new_str_hash;
-
-// FIXME: import std.util.option and use it here.
-// import std.util.option;
-
-tag option[T] {
- none;
- some(T);
-}
-
+import util.common.option;
+import util.common.some;
+import util.common.none;
state type parser =
state obj {
@@ -414,8 +408,35 @@ io fn parse_or_expr(parser p) -> @ast.expr {
ret parse_binary_exprs(p, sub, vec(tup(token.OROR, ast.or)));
}
+io fn parse_if_expr(parser p) -> @ast.expr {
+ expect(p, token.IF);
+ expect(p, token.LPAREN);
+ auto cond = parse_expr(p);
+ expect(p, token.RPAREN);
+ auto thn = parse_block(p);
+ let option[ast.block] els = none[ast.block];
+ alt (p.peek()) {
+ case (token.ELSE) {
+ p.bump();
+ els = some(parse_block(p));
+ }
+ }
+ ret @ast.expr_if(cond, thn, els);
+}
+
io fn parse_expr(parser p) -> @ast.expr {
- ret parse_or_expr(p);
+ alt (p.peek()) {
+ case (token.LBRACE) {
+ ret @ast.expr_block(parse_block(p));
+ }
+ case (token.IF) {
+ ret parse_if_expr(p);
+ }
+ case (_) {
+ ret parse_or_expr(p);
+ }
+
+ }
}
io fn parse_stmt(parser p) -> @ast.stmt {
@@ -426,6 +447,25 @@ io fn parse_stmt(parser p) -> @ast.stmt {
expect(p, token.SEMI);
ret @ast.stmt_log(e);
}
+
+ // Handle the (few) block-expr stmts first.
+
+ case (token.IF) {
+ ret @ast.stmt_expr(parse_expr(p));
+ }
+
+ case (token.LBRACE) {
+ ret @ast.stmt_expr(parse_expr(p));
+ }
+
+
+ // Remainder are line-expr stmts.
+
+ case (_) {
+ auto e = parse_expr(p);
+ expect(p, token.SEMI);
+ ret @ast.stmt_expr(e);
+ }
}
p.err("expected statement");
fail;
diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs
index f0cb65a2..220af154 100644
--- a/src/comp/lib/llvm.rs
+++ b/src/comp/lib/llvm.rs
@@ -1006,8 +1006,14 @@ obj builder(BuilderRef B) {
/* Miscellaneous instructions */
- fn Phi(TypeRef Ty) -> ValueRef {
- ret llvm.LLVMBuildPhi(B, Ty, _str.buf(""));
+ fn Phi(TypeRef Ty, vec[ValueRef] vals, vec[BasicBlockRef] bbs) -> ValueRef {
+ auto phi = llvm.LLVMBuildPhi(B, Ty, _str.buf(""));
+ check (_vec.len[ValueRef](vals) == _vec.len[BasicBlockRef](bbs));
+ llvm.LLVMAddIncoming(phi,
+ _vec.buf[ValueRef](vals),
+ _vec.buf[BasicBlockRef](bbs),
+ _vec.len[ValueRef](vals));
+ ret phi;
}
fn Call(ValueRef Fn, vec[ValueRef] Args) -> ValueRef {
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index f7147abf..ea64e060 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -11,6 +11,9 @@ import back.abi;
import util.common.istr;
import util.common.new_str_hash;
+import util.common.option;
+import util.common.some;
+import util.common.none;
import lib.llvm.llvm;
import lib.llvm.builder;
@@ -51,7 +54,7 @@ state type fn_ctxt = rec(ValueRef llfn,
type terminator = fn(@fn_ctxt cx, builder build);
tag cleanup {
- clean(fn(@block_ctxt cx) -> @block_ctxt);
+ clean(fn(@block_ctxt cx) -> result);
}
state type block_ctxt = rec(BasicBlockRef llbb,
@@ -61,6 +64,14 @@ state type block_ctxt = rec(BasicBlockRef llbb,
@fn_ctxt fcx);
+state type result = rec(mutable @block_ctxt bcx,
+ mutable ValueRef val);
+
+fn res(@block_ctxt bcx, ValueRef val) -> result {
+ ret rec(mutable bcx = bcx,
+ mutable val = val);
+}
+
fn ty_str(TypeRef t) -> str {
ret lib.llvm.type_to_str(t);
}
@@ -76,10 +87,25 @@ fn val_str(ValueRef v) -> str {
// LLVM type constructors.
-fn T_nil() -> TypeRef {
+fn T_void() -> TypeRef {
+ // Note: For the time being llvm is kinda busted here, it has the notion
+ // of a 'void' type that can only occur as part of the signature of a
+ // function, but no general unit type of 0-sized value. This is, afaict,
+ // vestigial from its C heritage, and we'll be attempting to submit a
+ // patch upstream to fix it. In the mean time we only model function
+ // outputs (Rust functions and C functions) using T_void, and model the
+ // Rust general purpose nil type you can construct as 1-bit (always
+ // zero). This makes the result incorrect for now -- things like a tuple
+ // of 10 nil values will have 10-bit size -- but it doesn't seem like we
+ // have any other options until it's fixed upstream.
ret llvm.LLVMVoidType();
}
+fn T_nil() -> TypeRef {
+ // NB: See above in T_void().
+ ret llvm.LLVMInt1Type();
+}
+
fn T_i1() -> TypeRef {
ret llvm.LLVMInt1Type();
}
@@ -196,6 +222,11 @@ fn C_integral(int i, TypeRef t) -> ValueRef {
ret llvm.LLVMConstIntOfString(t, _str.buf(istr(i)), 10);
}
+fn C_nil() -> ValueRef {
+ // NB: See comment above in T_void().
+ ret C_integral(0, T_i1());
+}
+
fn C_bool(bool b) -> ValueRef {
if (b) {
ret C_integral(1, T_i1());
@@ -233,7 +264,7 @@ fn decl_cdecl_fn(ModuleRef llmod, str name,
}
fn decl_glue(ModuleRef llmod, str s) -> ValueRef {
- ret decl_cdecl_fn(llmod, s, vec(T_taskptr()), T_nil());
+ ret decl_cdecl_fn(llmod, s, vec(T_taskptr()), T_void());
}
fn decl_upcall(ModuleRef llmod, uint _n) -> ValueRef {
@@ -263,7 +294,7 @@ fn get_upcall(@trans_ctxt cx, str name, int n_args) -> ValueRef {
ret f;
}
-fn trans_upcall(@block_ctxt cx, str name, vec[ValueRef] args) -> ValueRef {
+fn trans_upcall(@block_ctxt cx, str name, vec[ValueRef] args) -> result {
let int n = _vec.len[ValueRef](args) as int;
let ValueRef llupcall = get_upcall(cx.fcx.tcx, name, n);
llupcall = llvm.LLVMConstPointerCast(llupcall, T_int());
@@ -281,171 +312,239 @@ fn trans_upcall(@block_ctxt cx, str name, vec[ValueRef] args) -> ValueRef {
log "emitting call to llglue of type: " + val_str(llglue);
*/
- ret cx.build.Call(llglue, call_args);
+ ret res(cx, cx.build.Call(llglue, call_args));
}
-fn build_non_gc_free(@block_ctxt cx, ValueRef v) {
- trans_upcall(cx, "upcall_free", vec(cx.build.PtrToInt(v, T_int()),
- C_int(0)));
+fn trans_non_gc_free(@block_ctxt cx, ValueRef v) -> result {
+ ret trans_upcall(cx, "upcall_free", vec(cx.build.PtrToInt(v, T_int()),
+ C_int(0)));
}
fn decr_refcnt_and_if_zero(@block_ctxt cx,
ValueRef box_ptr,
- fn(@block_ctxt cx) inner) -> @block_ctxt {
+ fn(@block_ctxt cx) -> result inner,
+ TypeRef t_else, ValueRef v_else) -> result {
auto rc_ptr = cx.build.GEP(box_ptr, vec(C_int(0),
C_int(abi.box_rc_field_refcnt)));
auto rc = cx.build.Load(rc_ptr);
rc = cx.build.Sub(rc, C_int(1));
cx.build.Store(rc, rc_ptr);
auto test = cx.build.ICmp(lib.llvm.LLVMIntEQ, C_int(0), rc);
- auto next_cx = new_block_ctxt(cx.fcx, cx.term);
- // We terminate the then-block ourselves here with a Br, so
- // the terminator we pass in to the inner call is the no-op.
- auto then_term = terminate_no_op;
- auto then_cx = new_block_ctxt(cx.fcx, then_term);
- inner(then_cx);
- then_cx.build.Br(next_cx.llbb);
- cx.build.CondBr(test, then_cx.llbb, next_cx.llbb);
- ret next_cx;
+ auto next_cx = new_extension_block_ctxt(cx);
+ auto then_cx = new_empty_block_ctxt(cx.fcx);
+ auto then_res = inner(then_cx);
+ then_res.bcx.build.Br(next_cx.llbb);
+ cx.build.CondBr(test, then_res.bcx.llbb, next_cx.llbb);
+ auto phi = next_cx.build.Phi(t_else,
+ vec(v_else, then_res.val),
+ vec(cx.llbb, then_res.bcx.llbb));
+ ret res(next_cx, phi);
}
-fn drop_str(@block_ctxt cx, ValueRef v) -> @block_ctxt {
- ret decr_refcnt_and_if_zero(cx, v, bind build_non_gc_free(_, v));
+fn trans_drop_str(@block_ctxt cx, ValueRef v) -> result {
+ ret decr_refcnt_and_if_zero(cx, v,
+ bind trans_non_gc_free(_, v),
+ T_int(), C_int(0));
}
-fn trans_lit(@block_ctxt cx, &ast.lit lit) -> ValueRef {
+fn trans_lit(@block_ctxt cx, &ast.lit lit) -> result {
alt (lit) {
case (ast.lit_int(?i)) {
- ret C_int(i);
+ ret res(cx, C_int(i));
}
case (ast.lit_uint(?u)) {
- ret C_int(u as int);
+ ret res(cx, C_int(u as int));
}
case (ast.lit_char(?c)) {
- ret C_integral(c as int, T_i32());
+ ret res(cx, C_integral(c as int, T_i32()));
}
case (ast.lit_bool(?b)) {
- ret C_bool(b);
+ ret res(cx, C_bool(b));
+ }
+ case (ast.lit_nil) {
+ ret res(cx, C_nil());
}
case (ast.lit_str(?s)) {
auto len = (_str.byte_len(s) as int) + 1;
- auto v = trans_upcall(cx, "upcall_new_str",
- vec(p2i(C_str(cx.fcx.tcx, s)),
- C_int(len)));
- v = cx.build.IntToPtr(v, T_ptr(T_str(len as uint)));
- cx.cleanups += vec(clean(bind drop_str(_, v)));
- ret v;
+ auto sub = trans_upcall(cx, "upcall_new_str",
+ vec(p2i(C_str(cx.fcx.tcx, s)),
+ C_int(len)));
+ sub.val = sub.bcx.build.IntToPtr(sub.val,
+ T_ptr(T_str(len as uint)));
+ cx.cleanups += vec(clean(bind trans_drop_str(_, sub.val)));
+ ret sub;
}
}
}
-fn trans_unary(@block_ctxt cx, ast.unop op, &ast.expr e) -> ValueRef {
+fn trans_unary(@block_ctxt cx, ast.unop op, &ast.expr e) -> result {
+
+ auto sub = trans_expr(cx, e);
+
alt (op) {
case (ast.bitnot) {
- ret cx.build.Not(trans_expr(cx, e));
+ sub.val = cx.build.Not(sub.val);
+ ret sub;
}
case (ast.not) {
- ret cx.build.Not(trans_expr(cx, e));
+ sub.val = cx.build.Not(sub.val);
+ ret sub;
}
case (ast.neg) {
// FIXME: switch by signedness.
- ret cx.build.Neg(trans_expr(cx, e));
+ sub.val = cx.build.Neg(sub.val);
+ ret sub;
}
-
}
cx.fcx.tcx.sess.unimpl("expr variant in trans_unary");
fail;
}
fn trans_binary(@block_ctxt cx, ast.binop op,
- &ast.expr a, &ast.expr b) -> ValueRef {
+ &ast.expr a, &ast.expr b) -> result {
+
+ auto lhs = trans_expr(cx, a);
+ auto sub = trans_expr(lhs.bcx, b);
+
alt (op) {
case (ast.add) {
- ret cx.build.Add(trans_expr(cx, a), trans_expr(cx, b));
+ sub.val = cx.build.Add(lhs.val, sub.val);
+ ret sub;
}
case (ast.sub) {
- ret cx.build.Sub(trans_expr(cx, a), trans_expr(cx, b));
+ sub.val = cx.build.Sub(lhs.val, sub.val);
+ ret sub;
}
case (ast.mul) {
// FIXME: switch by signedness.
- ret cx.build.Mul(trans_expr(cx, a), trans_expr(cx, b));
+ sub.val = cx.build.Mul(lhs.val, sub.val);
+ ret sub;
}
case (ast.div) {
// FIXME: switch by signedness.
- ret cx.build.SDiv(trans_expr(cx, a), trans_expr(cx, b));
+ sub.val = cx.build.SDiv(lhs.val, sub.val);
+ ret sub;
}
case (ast.rem) {
// FIXME: switch by signedness.
- ret cx.build.SRem(trans_expr(cx, a), trans_expr(cx, b));
+ sub.val = cx.build.SRem(lhs.val, sub.val);
+ ret sub;
}
case (ast.bitor) {
- ret cx.build.Or(trans_expr(cx, a), trans_expr(cx, b));
+ sub.val = cx.build.Or(lhs.val, sub.val);
+ ret sub;
}
case (ast.bitand) {
- ret cx.build.And(trans_expr(cx, a), trans_expr(cx, b));
+ sub.val = cx.build.And(lhs.val, sub.val);
+ ret sub;
}
case (ast.bitxor) {
- ret cx.build.Xor(trans_expr(cx, a), trans_expr(cx, b));
+ sub.val = cx.build.Xor(lhs.val, sub.val);
+ ret sub;
}
case (ast.lsl) {
- ret cx.build.Shl(trans_expr(cx, a), trans_expr(cx, b));
+ sub.val = cx.build.Shl(lhs.val, sub.val);
+ ret sub;
}
case (ast.lsr) {
- ret cx.build.LShr(trans_expr(cx, a), trans_expr(cx, b));
+ sub.val = cx.build.LShr(lhs.val, sub.val);
+ ret sub;
}
case (ast.asr) {
- ret cx.build.AShr(trans_expr(cx, a), trans_expr(cx, b));
+ sub.val = cx.build.AShr(lhs.val, sub.val);
+ ret sub;
}
case (ast.eq) {
- ret cx.build.ICmp(lib.llvm.LLVMIntEQ,
- trans_expr(cx, a), trans_expr(cx, b));
+ sub.val = cx.build.ICmp(lib.llvm.LLVMIntEQ, lhs.val, sub.val);
+ ret sub;
}
case (ast.ne) {
- ret cx.build.ICmp(lib.llvm.LLVMIntNE,
- trans_expr(cx, a), trans_expr(cx, b));
+ sub.val = cx.build.ICmp(lib.llvm.LLVMIntNE, lhs.val, sub.val);
+ ret sub;
}
case (ast.lt) {
// FIXME: switch by signedness.
- ret cx.build.ICmp(lib.llvm.LLVMIntSLT,
- trans_expr(cx, a), trans_expr(cx, b));
+ sub.val = cx.build.ICmp(lib.llvm.LLVMIntSLT, lhs.val, sub.val);
+ ret sub;
}
case (ast.le) {
// FIXME: switch by signedness.
- ret cx.build.ICmp(lib.llvm.LLVMIntSLE,
- trans_expr(cx, a), trans_expr(cx, b));
+ sub.val = cx.build.ICmp(lib.llvm.LLVMIntSLE, lhs.val, sub.val);
+ ret sub;
}
case (ast.ge) {
// FIXME: switch by signedness.
- ret cx.build.ICmp(lib.llvm.LLVMIntSGE,
- trans_expr(cx, a), trans_expr(cx, b));
+ sub.val = cx.build.ICmp(lib.llvm.LLVMIntSGE, lhs.val, sub.val);
+ ret sub;
}
case (ast.gt) {
// FIXME: switch by signedness.
- ret cx.build.ICmp(lib.llvm.LLVMIntSGT,
- trans_expr(cx, a), trans_expr(cx, b));
+ sub.val = cx.build.ICmp(lib.llvm.LLVMIntSGT, lhs.val, sub.val);
+ ret sub;
}
}
cx.fcx.tcx.sess.unimpl("expr variant in trans_binary");
fail;
}
-fn trans_expr(@block_ctxt cx, &ast.expr e) -> ValueRef {
+fn trans_if(@block_ctxt cx, &ast.expr cond,
+ &ast.block thn, &option[ast.block] els) -> result {
+
+ auto cond_res = trans_expr(cx, cond);
+
+ auto then_cx = new_empty_block_ctxt(cx.fcx);
+ auto then_res = trans_block(then_cx, thn);
+
+ auto next_cx = new_extension_block_ctxt(cx);
+ then_res.bcx.build.Br(next_cx.llbb);
+ auto phi;
+
+ alt (els) {
+ case (some[ast.block](?eblk)) {
+ auto else_cx = new_empty_block_ctxt(cx.fcx);
+ auto else_res = trans_block(else_cx, eblk);
+ cond_res.bcx.build.CondBr(cond_res.val,
+ then_cx.llbb,
+ else_cx.llbb);
+ else_res.bcx.build.Br(next_cx.llbb);
+ phi = next_cx.build.Phi(T_nil(),
+ vec(then_res.val,
+ else_res.val),
+ vec(then_res.bcx.llbb,
+ else_res.bcx.llbb));
+ }
+
+ case (_) {
+ cond_res.bcx.build.CondBr(cond_res.val,
+ then_cx.llbb,
+ next_cx.llbb);
+ phi = next_cx.build.Phi(T_nil(),
+ vec(then_res.val, C_nil()),
+ vec(then_res.bcx.llbb,
+ cond_res.bcx.llbb));
+ }
+ }
+
+ ret res(next_cx, phi);
+}
+
+fn trans_expr(@block_ctxt cx, &ast.expr e) -> result {
alt (e) {
case (ast.expr_lit(?lit)) {
ret trans_lit(cx, *lit);
@@ -458,54 +557,70 @@ fn trans_expr(@block_ctxt cx, &ast.expr e) -> ValueRef {
case (ast.expr_binary(?op, ?x, ?y)) {
ret trans_binary(cx, op, *x, *y);
}
+
+ case (ast.expr_if(?cond, ?thn, ?els)) {
+ ret trans_if(cx, *cond, thn, els);
+ }
+
+ case (ast.expr_block(?blk)) {
+ auto sub_cx = new_empty_block_ctxt(cx.fcx);
+ auto next_cx = new_extension_block_ctxt(cx);
+ auto sub = trans_block(sub_cx, blk);
+
+ cx.build.Br(sub_cx.llbb);
+ sub.bcx.build.Br(next_cx.llbb);
+
+ ret res(next_cx, sub.val);
+ }
}
cx.fcx.tcx.sess.unimpl("expr variant in trans_expr");
fail;
}
-fn trans_log(@block_ctxt cx, &ast.expr e) {
+fn trans_log(@block_ctxt cx, &ast.expr e) -> result {
alt (e) {
case (ast.expr_lit(?lit)) {
alt (*lit) {
case (ast.lit_str(_)) {
- auto v = trans_expr(cx, e);
- trans_upcall(cx, "upcall_log_str",
- vec(cx.build.PtrToInt(v, T_int())));
+ auto sub = trans_expr(cx, e);
+ auto v = sub.bcx.build.PtrToInt(sub.val, T_int());
+ ret trans_upcall(sub.bcx,
+ "upcall_log_str",
+ vec(v));
}
+
case (_) {
- auto v = trans_expr(cx, e);
- trans_upcall(cx, "upcall_log_int", vec(v));
+ auto sub = trans_expr(cx, e);
+ ret trans_upcall(sub.bcx,
+ "upcall_log_int",
+ vec(sub.val));
}
}
}
+
case (_) {
- auto v = trans_expr(cx, e);
- trans_upcall(cx, "upcall_log_int", vec(v));
+ auto sub = trans_expr(cx, e);
+ ret trans_upcall(sub.bcx, "upcall_log_int", vec(sub.val));
}
}
}
-fn trans_stmt(@block_ctxt cx, &ast.stmt s) {
+fn trans_stmt(@block_ctxt cx, &ast.stmt s) -> result {
+ auto sub = res(cx, C_nil());
alt (s) {
case (ast.stmt_log(?a)) {
- trans_log(cx, *a);
+ sub.bcx = trans_log(cx, *a).bcx;
+ }
+
+ case (ast.stmt_expr(?e)) {
+ sub.bcx = trans_expr(cx, *e).bcx;
}
+
case (_) {
cx.fcx.tcx.sess.unimpl("stmt variant");
}
}
-}
-
-fn terminate_ret_void(@fn_ctxt cx, builder build) {
- build.RetVoid();
-}
-
-
-fn terminate_branch_to(@fn_ctxt cx, builder build, BasicBlockRef bb) {
- build.Br(bb);
-}
-
-fn terminate_no_op(@fn_ctxt cx, builder build) {
+ ret sub;
}
fn new_builder(BasicBlockRef llbb) -> builder {
@@ -514,10 +629,12 @@ fn new_builder(BasicBlockRef llbb) -> builder {
ret builder(llbuild);
}
-fn new_block_ctxt(@fn_ctxt cx, terminator term) -> @block_ctxt {
+// You probably don't want to use this one. See the
+// next three functions instead.
+fn new_block_ctxt(@fn_ctxt cx, terminator term,
+ vec[cleanup] cleanups) -> @block_ctxt {
let BasicBlockRef llbb =
llvm.LLVMAppendBasicBlock(cx.llfn, _str.buf(""));
- let vec[cleanup] cleanups = vec();
ret @rec(llbb=llbb,
build=new_builder(llbb),
term=term,
@@ -525,21 +642,59 @@ fn new_block_ctxt(@fn_ctxt cx, terminator term) -> @block_ctxt {
fcx=cx);
}
-fn trans_block(@fn_ctxt cx, &ast.block b, terminator term) {
- auto bcx = (new_block_ctxt(cx, term));
- for (@ast.stmt s in b) {
- trans_stmt(bcx, *s);
+// Use this when you are making a block_ctxt to replace the
+// current one, i.e. when chaining together sequences of stmts
+// or making sub-blocks you will branch back out of and wish to
+// "carry on" in the parent block's context.
+fn new_extension_block_ctxt(@block_ctxt bcx) -> @block_ctxt {
+ ret new_block_ctxt(bcx.fcx, bcx.term, bcx.cleanups);
+}
+
+// Use this when you're at the top block of a function or the like.
+fn new_top_block_ctxt(@fn_ctxt fcx) -> @block_ctxt {
+ fn terminate_ret_void(@fn_ctxt cx, builder build) {
+ build.RetVoid();
+ }
+ auto term = terminate_ret_void;
+ let vec[cleanup] cleanups = vec();
+ ret new_block_ctxt(fcx, term, cleanups);
+
+}
+
+// Use this when you are making a block_ctxt to replace the
+// current one, i.e. when chaining together sequences of stmts
+// or making sub-blocks you will branch back out of and wish to
+// "carry on" in the parent block's context.
+fn new_empty_block_ctxt(@fn_ctxt fcx) -> @block_ctxt {
+ fn terminate_no_op(@fn_ctxt cx, builder build) {
}
+ auto term = terminate_no_op;
+ let vec[cleanup] cleanups = vec();
+ ret new_block_ctxt(fcx, term, cleanups);
+}
- for (cleanup c in bcx.cleanups) {
+fn trans_block_cleanups(@block_ctxt cx) -> @block_ctxt {
+ auto bcx = cx;
+ for (cleanup c in cx.cleanups) {
alt (c) {
case (clean(?cfn)) {
- bcx = cfn(bcx);
+ bcx = cfn(bcx).bcx;
}
}
}
+ ret bcx;
+}
+
+fn trans_block(@block_ctxt cx, &ast.block b) -> result {
+ auto bcx = cx;
+
+ for (@ast.stmt s in b) {
+ bcx = trans_stmt(bcx, *s).bcx;
+ }
- bcx.term(cx, bcx.build);
+ bcx = trans_block_cleanups(bcx);
+ bcx.term(bcx.fcx, bcx.build);
+ ret res(bcx, C_nil());
}
fn new_fn_ctxt(@trans_ctxt cx,
@@ -550,7 +705,7 @@ fn new_fn_ctxt(@trans_ctxt cx,
T_taskptr() // taskptr
);
args += T_explicit_args;
- let ValueRef llfn = decl_cdecl_fn(cx.llmod, name, args, T_nil());
+ let ValueRef llfn = decl_cdecl_fn(cx.llmod, name, args, T_void());
cx.fns.insert(cx.path, llfn);
let ValueRef lloutptr = llvm.LLVMGetParam(llfn, 0u);
let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 1u);
@@ -565,9 +720,8 @@ fn trans_fn(@trans_ctxt cx, &ast._fn f) {
let vec[TypeRef] args = vec();
auto fcx = new_fn_ctxt(cx, cx.path, out, args);
- auto term = terminate_ret_void;
- trans_block(fcx, f.body, term);
+ trans_block(new_top_block_ctxt(fcx), f.body);
}
fn trans_item(@trans_ctxt cx, &str name, &ast.item item) {
@@ -596,7 +750,6 @@ fn p2i(ValueRef v) -> ValueRef {
fn trans_exit_task_glue(@trans_ctxt cx) {
let vec[TypeRef] T_args = vec();
let vec[ValueRef] V_args = vec();
- auto term = terminate_ret_void;
auto llfn = cx.glues.exit_task_glue;
let ValueRef lloutptr = C_null(T_int());
@@ -606,7 +759,7 @@ fn trans_exit_task_glue(@trans_ctxt cx) {
lltaskptr=lltaskptr,
tcx=cx);
- auto bcx = new_block_ctxt(fcx, term);
+ auto bcx = new_top_block_ctxt(fcx);
trans_upcall(bcx, "upcall_exit", V_args);
bcx.term(fcx, bcx.build);
}
@@ -705,7 +858,7 @@ fn trans_crate(session.session sess, ast.crate crate) {
*/
exit_task_glue =
decl_cdecl_fn(llmod, abi.exit_task_glue_name(),
- vec(T_taskptr()), T_nil()),
+ vec(T_taskptr()), T_void()),
upcall_glues =
_vec.init_fn[ValueRef](bind decl_upcall(llmod, _),
diff --git a/src/comp/util/common.rs b/src/comp/util/common.rs
index 7456a8c8..7b0ffd5b 100644
--- a/src/comp/util/common.rs
+++ b/src/comp/util/common.rs
@@ -4,6 +4,14 @@ import std._int;
type pos = rec(uint line, uint col);
type span = rec(str filename, pos lo, pos hi);
+// FIXME: import std.util.option and use it here.
+// import std.util.option;
+
+tag option[T] {
+ none;
+ some(T);
+}
+
tag ty_mach {
ty_i8;
ty_i16;