Merge branch 'unwind'

Conflicts:
	src/comp/middle/trans.rs
	src/comp/middle/trans_build.rs
	src/lib/run_program.rs
	src/test/compiletest/runtest.rs
This commit is contained in:
Brian Anderson 2011-09-12 09:36:51 -07:00
commit 393deeb06f
49 changed files with 491 additions and 106 deletions

View file

@ -37,7 +37,8 @@ type upcalls =
log_type: ValueRef,
dynastack_mark: ValueRef,
dynastack_alloc: ValueRef,
dynastack_free: ValueRef};
dynastack_free: ValueRef,
rust_personality: ValueRef};
fn declare_upcalls(_tn: type_names, tydesc_type: TypeRef,
taskptr_type: TypeRef, llmod: ModuleRef) -> @upcalls {
@ -89,7 +90,9 @@ fn declare_upcalls(_tn: type_names, tydesc_type: TypeRef,
dynastack_alloc:
d("dynastack_alloc_2", [T_size_t(), T_ptr(tydesc_type)],
T_ptr(T_i8())),
dynastack_free: d("dynastack_free", [T_ptr(T_i8())], T_void())};
dynastack_free: d("dynastack_free", [T_ptr(T_i8())], T_void()),
rust_personality: dr("rust_personality", [], T_i32())
};
}
//
// Local Variables:

View file

@ -572,6 +572,9 @@ native "cdecl" mod llvm = "rustllvm" {
fn LLVMBuildInvoke(B: BuilderRef, Fn: ValueRef, Args: *ValueRef,
NumArgs: uint, Then: BasicBlockRef,
Catch: BasicBlockRef, Name: sbuf) -> ValueRef;
fn LLVMBuildLandingPad(B: BuilderRef, Ty: TypeRef, PersFn: ValueRef,
NumClauses: uint, Name: sbuf) -> ValueRef;
fn LLVMBuildResume(B: BuilderRef, Exn: ValueRef) -> ValueRef;
fn LLVMBuildUnreachable(B: BuilderRef) -> ValueRef;
/* Add a case to the switch instruction */
@ -580,6 +583,12 @@ native "cdecl" mod llvm = "rustllvm" {
/* Add a destination to the indirectbr instruction */
fn LLVMAddDestination(IndirectBr: ValueRef, Dest: BasicBlockRef);
/* Add a clause to the landing pad instruction */
fn LLVMAddClause(LandingPad: ValueRef, ClauseVal: ValueRef);
/* Set the cleanup on a landing pad instruction */
fn LLVMSetCleanup(LandingPad: ValueRef, Val: Bool);
/* Arithmetic */
fn LLVMBuildAdd(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, Name: sbuf)
-> ValueRef;

View file

@ -3715,7 +3715,7 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
for the call itself is unreachable. */
let retval = C_nil();
if !is_terminated(bcx) {
FastCall(bcx, faddr, llargs);
bcx = invoke_fastcall(bcx, faddr, llargs).bcx;
alt lliterbody {
none. {
if !ty::type_is_nil(bcx_tcx(cx), ret_ty) {
@ -3748,6 +3748,67 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
ret rslt(bcx, retval);
}
fn invoke(bcx: @block_ctxt, llfn: ValueRef,
llargs: [ValueRef]) -> result {
ret invoke_(bcx, llfn, llargs, Invoke);
}
fn invoke_fastcall(bcx: @block_ctxt, llfn: ValueRef,
llargs: [ValueRef]) -> result {
ret invoke_(bcx, llfn, llargs, FastInvoke);
}
fn invoke_(bcx: @block_ctxt, llfn: ValueRef,
llargs: [ValueRef],
invoker: fn(@block_ctxt, ValueRef, [ValueRef],
BasicBlockRef, BasicBlockRef) -> ValueRef) -> result {
// FIXME: May be worth turning this into a plain call when there are no
// cleanups to run
let normal_bcx = new_sub_block_ctxt(bcx, "normal return");
let unwind_bcx = new_sub_block_ctxt(bcx, "unwind");
let retval = invoker(bcx, llfn, llargs,
normal_bcx.llbb,
unwind_bcx.llbb);
trans_landing_pad(unwind_bcx);
ret rslt(normal_bcx, retval);
}
fn trans_landing_pad(bcx: @block_ctxt) {
// The landing pad return type (the type being propagated). Not sure what
// this represents but it's determined by the personality function and
// this is what the EH proposal example uses.
let llretty = T_struct([T_ptr(T_i8()), T_i32()]);
// The exception handling personality function. This is the C++
// personality function __gxx_personality_v0, wrapped in our naming
// convention.
let personality = bcx_ccx(bcx).upcalls.rust_personality;
// The only landing pad clause will be 'cleanup'
let clauses = 1u;
let llpad = LandingPad(bcx, llretty, personality, clauses);
// The landing pad result is used both for modifying the landing pad
// in the C API and as the exception value
let llretval = llpad;
// The landing pad block is a cleanup
SetCleanup(bcx, llpad);
// FIXME: This seems like a very naive and redundant way to generate the
// landing pads, as we're re-generating all in-scope cleanups for each
// function call. Probably good optimization opportunities here.
let bcx = bcx;
let scope_cx = bcx;
while true {
scope_cx = find_scope_cx(scope_cx);
bcx = trans_block_cleanups(bcx, scope_cx);
scope_cx = alt scope_cx.parent {
parent_some(b) { b }
parent_none. { break; }
};
}
// Continue unwinding
Resume(bcx, llretval);
}
fn trans_tup(cx: @block_ctxt, elts: [@ast::expr], id: ast::node_id) ->
result {
let bcx = cx;
@ -4211,7 +4272,7 @@ fn trans_fail_value(cx: @block_ctxt, sp_opt: option::t<span>,
let V_str = PointerCast(cx, V_fail_str, T_ptr(T_i8()));
V_filename = PointerCast(cx, V_filename, T_ptr(T_i8()));
let args = [cx.fcx.lltaskptr, V_str, V_filename, C_int(V_line)];
Call(cx, bcx_ccx(cx).upcalls._fail, args);
let cx = invoke(cx, bcx_ccx(cx).upcalls._fail, args).bcx;
Unreachable(cx);
ret rslt(cx, C_nil());
}
@ -4247,7 +4308,7 @@ fn trans_put(in_cx: @block_ctxt, e: option::t<@ast::expr>) -> result {
llargs += [r.val];
}
}
FastCall(bcx, llcallee, llargs);
bcx = invoke_fastcall(bcx, llcallee, llargs).bcx;
bcx = trans_block_cleanups(bcx, cx);
let next_cx = new_sub_block_ctxt(in_cx, "next");
Br(bcx, next_cx.llbb);
@ -4379,7 +4440,9 @@ fn init_local(bcx: @block_ctxt, local: @ast::local) -> result {
// Make a note to drop this slot on the way out.
add_clean(bcx, llptr, ty);
if must_zero(local) { bcx = zero_alloca(bcx, llptr, ty).bcx; }
if must_zero(bcx_ccx(bcx), local) {
bcx = zero_alloca(bcx, llptr, ty).bcx;
}
alt local.node.init {
some(init) {
@ -4405,35 +4468,38 @@ fn init_local(bcx: @block_ctxt, local: @ast::local) -> result {
bcx.fcx.lllocals, false);
ret rslt(bcx, llptr);
fn must_zero(local: @ast::local) -> bool {
fn must_zero(ccx: @crate_ctxt, local: @ast::local) -> bool {
alt local.node.init {
some(init) { might_not_init(init.expr) }
some(init) { might_not_init(ccx, init.expr) }
none. { true }
}
}
fn might_not_init(expr: @ast::expr) -> bool {
type env = @mutable bool;
let e = @mutable false;
// FIXME: Probably also need to account for expressions that
// fail but since we don't unwind yet, it doesn't seem to be a
// problem
fn might_not_init(ccx: @crate_ctxt, expr: @ast::expr) -> bool {
type env = {mutable mightnt: bool,
ccx: @crate_ctxt};
let e = {mutable mightnt: false,
ccx: ccx};
fn visit_expr(ex: @ast::expr, e: env, v: vt<env>) {
let might_not_init = alt ex.node {
ast::expr_ret(_) { true }
ast::expr_break. { true }
ast::expr_cont. { true }
ast::expr_call(_, _) { true }
_ {
let ex_ty = ty::expr_ty(e.ccx.tcx, ex);
ty::type_is_bot(e.ccx.tcx, ex_ty)
}
};
if might_not_init {
e.mightnt = true;
} else { visit::visit_expr(ex, e, v); }
}
let visitor =
visit::mk_vt(@{visit_expr:
fn (ex: @ast::expr, e: env, v: vt<env>) {
let might_not_init =
alt ex.node {
ast::expr_ret(_) { true }
ast::expr_break. { true }
ast::expr_cont. { true }
_ { false }
};
if might_not_init {
*e = true;
} else { visit::visit_expr(ex, e, v); }
} with *visit::default_visitor()});
visit::mk_vt(@{visit_expr: visit_expr
with *visit::default_visitor()});
visitor.visit_expr(expr, e, visitor);
ret *e;
ret e.mightnt;
}
}

View file

@ -68,6 +68,21 @@ fn Invoke(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef],
});
}
fn FastInvoke(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef],
Then: BasicBlockRef, Catch: BasicBlockRef) -> ValueRef {
assert (!cx.terminated);
cx.terminated = true;
let v = str::as_buf("",
{|buf|
llvm::LLVMBuildInvoke(B(cx), Fn,
vec::to_ptr(Args),
vec::len(Args), Then,
Catch, buf)
});
llvm::LLVMSetInstructionCallConv(v, lib::llvm::LLVMFastCallConv);
ret v;
}
fn Unreachable(cx: @block_ctxt) -> ValueRef {
assert (!cx.terminated);
cx.terminated = true;
@ -527,6 +542,29 @@ fn Trap(cx: @block_ctxt) -> ValueRef {
});
}
fn LandingPad(cx: @block_ctxt, Ty: TypeRef, PersFn: ValueRef,
NumClauses: uint) -> ValueRef {
assert (!cx.terminated);
ret str::as_buf("",
{|buf|
llvm::LLVMBuildLandingPad(B(cx),
Ty,
PersFn,
NumClauses,
buf)
});
}
fn SetCleanup(_cx: @block_ctxt, LandingPad: ValueRef) {
llvm::LLVMSetCleanup(LandingPad, lib::llvm::True);
}
fn Resume(cx: @block_ctxt, Exn: ValueRef) -> ValueRef {
assert (!cx.terminated);
cx.terminated = true;
ret llvm::LLVMBuildResume(B(cx), Exn);
}
//
// Local Variables:
// mode: rust