Redo the scheme for block context chaining and termination, to simplify and support ret better.
This commit is contained in:
parent
a404e54261
commit
d1e7f0b414
@ -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
|
||||
;;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user