aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGraydon Hoare <[email protected]>2010-11-10 17:46:49 -0800
committerGraydon Hoare <[email protected]>2010-11-10 17:46:49 -0800
commitd1e7f0b4146aaaf3aa54902de9eb2ac44ad01160 (patch)
treeabf363aa278a546ab3065c228cb068c270aec4c1
parentTeach rustc about const tag value, begin work on trans_copy_ty, make uint's t... (diff)
downloadrust-d1e7f0b4146aaaf3aa54902de9eb2ac44ad01160.tar.xz
rust-d1e7f0b4146aaaf3aa54902de9eb2ac44ad01160.zip
Redo the scheme for block context chaining and termination, to simplify and support ret better.
-rw-r--r--src/boot/me/semant.ml3
-rw-r--r--src/comp/lib/llvm.rs2
-rw-r--r--src/comp/middle/trans.rs156
3 files changed, 91 insertions, 70 deletions
diff --git a/src/boot/me/semant.ml b/src/boot/me/semant.ml
index c22e788b..4f02455a 100644
--- a/src/boot/me/semant.ml
+++ b/src/boot/me/semant.ml
@@ -1286,7 +1286,8 @@ let is_prim_type (t:Ast.ty) : bool =
| Ast.TY_uint
| Ast.TY_char
| Ast.TY_mach _
- | Ast.TY_bool -> true
+ | Ast.TY_bool
+ | Ast.TY_native _ -> true
| _ -> false
;;
diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs
index 456b82cd..d30bb3ba 100644
--- a/src/comp/lib/llvm.rs
+++ b/src/comp/lib/llvm.rs
@@ -679,6 +679,8 @@ native mod llvm = llvm_lib {
fn LLVMBuildPtrDiff(BuilderRef B, ValueRef LHS,
ValueRef RHS, sbuf Name) -> ValueRef;
+ /* Selected entries from the downcasts. */
+ fn LLVMIsATerminatorInst(ValueRef Inst) -> ValueRef;
/** Writes a module to the specified path. Returns 0 on success. */
fn LLVMWriteBitcodeToFile(ModuleRef M, sbuf Path) -> int;
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 65dd2938..d2afa467 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -57,18 +57,24 @@ state type fn_ctxt = rec(ValueRef llfn,
hashmap[ast.def_id, ValueRef] lllocals,
@trans_ctxt tcx);
-type terminator = fn(@fn_ctxt cx, builder build);
-
tag cleanup {
clean(fn(@block_ctxt cx) -> result);
}
state type block_ctxt = rec(BasicBlockRef llbb,
builder build,
- terminator term,
+ block_parent parent,
mutable vec[cleanup] cleanups,
@fn_ctxt fcx);
+// FIXME: we should be able to use option.t[@block_parent] here but
+// the infinite-tag check in rustboot gets upset.
+
+tag block_parent {
+ parent_none;
+ parent_some(@block_ctxt);
+}
+
state type result = rec(mutable @block_ctxt bcx,
mutable ValueRef val);
@@ -399,8 +405,8 @@ fn incr_refcnt(@block_ctxt cx, ValueRef box_ptr) -> result {
C_int(abi.box_rc_field_refcnt)));
auto rc = cx.build.Load(rc_ptr);
- auto next_cx = new_extension_block_ctxt(cx);
- auto rc_adj_cx = new_empty_block_ctxt(cx.fcx);
+ auto next_cx = new_sub_block_ctxt(cx, "next");
+ auto rc_adj_cx = new_sub_block_ctxt(cx, "rc++");
auto const_test = cx.build.ICmp(lib.llvm.LLVMIntEQ,
C_int(abi.const_refcount as int), rc);
@@ -416,32 +422,35 @@ fn incr_refcnt(@block_ctxt cx, ValueRef box_ptr) -> result {
fn decr_refcnt_and_if_zero(@block_ctxt cx,
ValueRef box_ptr,
fn(@block_ctxt cx) -> result inner,
+ str inner_name,
TypeRef t_else, ValueRef v_else) -> result {
+
+ auto rc_adj_cx = new_sub_block_ctxt(cx, "rc--");
+ auto inner_cx = new_sub_block_ctxt(cx, inner_name);
+ auto next_cx = new_sub_block_ctxt(cx, "next");
+
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);
- auto rc_adj_cx = new_empty_block_ctxt(cx.fcx);
- auto next_cx = new_extension_block_ctxt(cx);
-
auto const_test = cx.build.ICmp(lib.llvm.LLVMIntEQ,
C_int(abi.const_refcount as int), rc);
cx.build.CondBr(const_test, next_cx.llbb, rc_adj_cx.llbb);
rc = rc_adj_cx.build.Sub(rc, C_int(1));
rc_adj_cx.build.Store(rc, rc_ptr);
-
auto zero_test = rc_adj_cx.build.ICmp(lib.llvm.LLVMIntEQ, C_int(0), rc);
+ rc_adj_cx.build.CondBr(zero_test, inner_cx.llbb, next_cx.llbb);
+
+ auto inner_res = inner(inner_cx);
+ inner_res.bcx.build.Br(next_cx.llbb);
- auto then_cx = new_empty_block_ctxt(cx.fcx);
- auto then_res = inner(then_cx);
- then_res.bcx.build.Br(next_cx.llbb);
- rc_adj_cx.build.CondBr(zero_test, then_res.bcx.llbb, next_cx.llbb);
auto phi = next_cx.build.Phi(t_else,
- vec(v_else, v_else, then_res.val),
+ vec(v_else, v_else, inner_res.val),
vec(cx.llbb,
rc_adj_cx.llbb,
- then_res.bcx.llbb));
+ inner_res.bcx.llbb));
+
ret res(next_cx, phi);
}
@@ -483,6 +492,7 @@ fn trans_copy_ty(@block_ctxt cx,
fn trans_drop_str(@block_ctxt cx, ValueRef v) -> result {
ret decr_refcnt_and_if_zero(cx, v,
bind trans_non_gc_free(_, v),
+ "free string",
T_int(), C_int(0));
}
@@ -571,10 +581,10 @@ impure fn trans_binary(@block_ctxt cx, ast.binop op,
// Lazy-eval and
auto lhs_res = trans_expr(cx, a);
- auto rhs_cx = new_empty_block_ctxt(cx.fcx);
+ auto rhs_cx = new_sub_block_ctxt(cx, "rhs");
auto rhs_res = trans_expr(rhs_cx, b);
- auto next_cx = new_extension_block_ctxt(cx);
+ auto next_cx = new_sub_block_ctxt(cx, "next");
rhs_res.bcx.build.Br(next_cx.llbb);
lhs_res.bcx.build.CondBr(lhs_res.val,
@@ -592,10 +602,10 @@ impure fn trans_binary(@block_ctxt cx, ast.binop op,
// Lazy-eval or
auto lhs_res = trans_expr(cx, a);
- auto rhs_cx = new_empty_block_ctxt(cx.fcx);
+ auto rhs_cx = new_sub_block_ctxt(cx, "rhs");
auto rhs_res = trans_expr(rhs_cx, b);
- auto next_cx = new_extension_block_ctxt(cx);
+ auto next_cx = new_sub_block_ctxt(cx, "next");
rhs_res.bcx.build.Br(next_cx.llbb);
lhs_res.bcx.build.CondBr(lhs_res.val,
@@ -717,16 +727,16 @@ impure fn trans_if(@block_ctxt cx, &ast.expr cond,
auto cond_res = trans_expr(cx, cond);
- auto then_cx = new_empty_block_ctxt(cx.fcx);
+ auto then_cx = new_sub_block_ctxt(cx, "then");
auto then_res = trans_block(then_cx, thn);
- auto next_cx = new_extension_block_ctxt(cx);
+ auto next_cx = new_sub_block_ctxt(cx, "next");
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_cx = new_sub_block_ctxt(cx, "else");
auto else_res = trans_block(else_cx, eblk);
cond_res.bcx.build.CondBr(cond_res.val,
then_cx.llbb,
@@ -756,9 +766,9 @@ impure fn trans_if(@block_ctxt cx, &ast.expr cond,
impure fn trans_while(@block_ctxt cx, &ast.expr cond,
&ast.block body) -> result {
- auto cond_cx = new_empty_block_ctxt(cx.fcx);
- auto body_cx = new_empty_block_ctxt(cx.fcx);
- auto next_cx = new_extension_block_ctxt(cx);
+ auto cond_cx = new_sub_block_ctxt(cx, "while cond");
+ auto body_cx = new_sub_block_ctxt(cx, "while loop body");
+ auto next_cx = new_sub_block_ctxt(cx, "next");
auto body_res = trans_block(body_cx, body);
auto cond_res = trans_expr(cond_cx, cond);
@@ -775,8 +785,8 @@ impure fn trans_while(@block_ctxt cx, &ast.expr cond,
impure fn trans_do_while(@block_ctxt cx, &ast.block body,
&ast.expr cond) -> result {
- auto body_cx = new_empty_block_ctxt(cx.fcx);
- auto next_cx = new_extension_block_ctxt(cx);
+ auto body_cx = new_sub_block_ctxt(cx, "do-while loop body");
+ auto next_cx = new_sub_block_ctxt(cx, "next");
auto body_res = trans_block(body_cx, body);
auto cond_res = trans_expr(body_res.bcx, cond);
@@ -867,8 +877,8 @@ impure fn trans_expr(@block_ctxt cx, &ast.expr e) -> result {
}
case (ast.expr_block(?blk, _)) {
- auto sub_cx = new_empty_block_ctxt(cx.fcx);
- auto next_cx = new_extension_block_ctxt(cx);
+ auto sub_cx = new_sub_block_ctxt(cx, "block-expr body");
+ auto next_cx = new_sub_block_ctxt(cx, "next");
auto sub = trans_block(sub_cx, blk);
cx.build.Br(sub_cx.llbb);
@@ -958,10 +968,10 @@ impure fn trans_check_expr(@block_ctxt cx, &ast.expr e) -> result {
auto V_line = e.span.lo.line as int;
auto args = vec(V_expr_str, V_filename, C_int(V_line));
- auto fail_cx = new_empty_block_ctxt(cx.fcx);
+ auto fail_cx = new_sub_block_ctxt(cx, "fail");
auto fail_res = trans_upcall(fail_cx, "upcall_fail", args);
- auto next_cx = new_extension_block_ctxt(cx);
+ auto next_cx = new_sub_block_ctxt(cx, "next");
fail_res.bcx.build.Br(next_cx.llbb);
cond_res.bcx.build.CondBr(cond_res.val,
next_cx.llbb,
@@ -977,11 +987,23 @@ impure fn trans_ret(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
r.bcx.build.Store(r.val, cx.fcx.lloutptr);
}
}
- // FIXME: if we actually ret here, the block structure falls apart;
- // need to do something more-clever with terminators and block cleanup.
- // Mean time 'ret' means 'copy result to output slot and keep going'.
- // r.val = r.bcx.build.RetVoid();
+ // Run all cleanups and back out.
+ let bool more_cleanups = true;
+ auto bcx = cx;
+ while (more_cleanups) {
+ bcx = trans_block_cleanups(bcx);
+ alt (bcx.parent) {
+ case (parent_some(?b)) {
+ bcx = b;
+ }
+ case (parent_none) {
+ more_cleanups = false;
+ }
+ }
+ }
+
+ r.val = r.bcx.build.RetVoid();
ret r;
}
@@ -1024,7 +1046,7 @@ impure fn trans_stmt(@block_ctxt cx, &ast.stmt s) -> result {
ret sub;
}
-fn new_builder(BasicBlockRef llbb) -> builder {
+fn new_builder(BasicBlockRef llbb, str name) -> builder {
let BuilderRef llbuild = llvm.LLVMCreateBuilder();
llvm.LLVMPositionBuilderAtEnd(llbuild, llbb);
ret builder(llbuild);
@@ -1032,47 +1054,34 @@ fn new_builder(BasicBlockRef llbb) -> builder {
// 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 {
+fn new_block_ctxt(@fn_ctxt cx, block_parent parent,
+ vec[cleanup] cleanups,
+ str name) -> @block_ctxt {
let BasicBlockRef llbb =
- llvm.LLVMAppendBasicBlock(cx.llfn, _str.buf(""));
+ llvm.LLVMAppendBasicBlock(cx.llfn,
+ _str.buf(cx.tcx.names.next(name)));
+
ret @rec(llbb=llbb,
- build=new_builder(llbb),
- term=term,
+ build=new_builder(llbb, name),
+ parent=parent,
mutable cleanups=cleanups,
fcx=cx);
}
-// 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);
+ ret new_block_ctxt(fcx, parent_none, cleanups, "function top level");
}
-// Use this when you are making a block_ctxt that starts with a fresh
-// terminator and empty cleanups (no locals, no implicit return when
-// falling off the end).
-fn new_empty_block_ctxt(@fn_ctxt fcx) -> @block_ctxt {
- fn terminate_no_op(@fn_ctxt cx, builder build) {
- }
- auto term = terminate_no_op;
+// Use this when you're making a block-within-a-block.
+fn new_sub_block_ctxt(@block_ctxt bcx, str n) -> @block_ctxt {
let vec[cleanup] cleanups = vec();
- ret new_block_ctxt(fcx, term, cleanups);
+ ret new_block_ctxt(bcx.fcx, parent_some(bcx), cleanups, n);
}
+
fn trans_block_cleanups(@block_ctxt cx) -> @block_ctxt {
auto bcx = cx;
for (cleanup c in cx.cleanups) {
@@ -1117,14 +1126,15 @@ impure fn trans_block(@block_ctxt cx, &ast.block b) -> result {
auto val = bcx.build.Alloca(ty);
cx.fcx.lllocals.insert(local.id, val);
}
+ auto r = res(bcx, C_nil());
for (@ast.stmt s in b.node.stmts) {
- bcx = trans_stmt(bcx, *s).bcx;
+ r = trans_stmt(bcx, *s);
+ bcx = r.bcx;
}
bcx = trans_block_cleanups(bcx);
- bcx.term(bcx.fcx, bcx.build);
- ret res(bcx, C_nil());
+ ret res(bcx, r.val);
}
fn new_fn_ctxt(@trans_ctxt cx,
@@ -1155,11 +1165,19 @@ fn new_fn_ctxt(@trans_ctxt cx,
tcx=cx);
}
+fn is_terminated(@block_ctxt cx) -> bool {
+ auto inst = llvm.LLVMGetLastInstruction(cx.llbb);
+ ret llvm.LLVMIsATerminatorInst(inst) as int != 0;
+}
+
impure fn trans_fn(@trans_ctxt cx, &ast._fn f, ast.def_id fid) {
auto fcx = new_fn_ctxt(cx, cx.path, f, fid);
-
- trans_block(new_top_block_ctxt(fcx), f.body);
+ auto bcx = new_top_block_ctxt(fcx);
+ auto res = trans_block(bcx, f.body);
+ if (!is_terminated(res.bcx)) {
+ res.bcx.build.RetVoid();
+ }
}
impure fn trans_item(@trans_ctxt cx, &ast.item item) {
@@ -1240,7 +1258,7 @@ fn trans_exit_task_glue(@trans_ctxt cx) {
auto bcx = new_top_block_ctxt(fcx);
trans_upcall(bcx, "upcall_exit", V_args);
- bcx.term(fcx, bcx.build);
+ bcx.build.RetVoid();
}
fn crate_constant(@trans_ctxt cx) -> ValueRef {
@@ -1312,7 +1330,7 @@ fn trans_main_fn(@trans_ctxt cx, ValueRef llcrate) {
let BasicBlockRef llbb =
llvm.LLVMAppendBasicBlock(llmain, _str.buf(""));
- auto b = new_builder(llbb);
+ auto b = new_builder(llbb, "");
auto start_args = vec(p2i(llrust_main), p2i(llcrate), llargc, llargv);