Move expr_binary into trans_expr_dps

Issue #667
This commit is contained in:
Marijn Haverbeke 2011-09-27 10:50:18 +02:00
parent 806e74fbf5
commit 8282f7fe80
3 changed files with 115 additions and 123 deletions

View file

@ -2158,10 +2158,7 @@ fn trans_lit(cx: @block_ctxt, lit: ast::lit, dest: dest) -> @block_ctxt {
alt lit.node {
ast::lit_str(s) { ret tvec::trans_str(cx, s, dest); }
_ {
let cell = alt dest { by_val(c) { c }
_ { bcx_ccx(cx).sess.span_note(lit.span, "here"); fail; }};
*cell = trans_crate_lit(bcx_ccx(cx), lit);
ret cx;
ret store_in_dest(cx, trans_crate_lit(bcx_ccx(cx), lit), dest);
}
}
}
@ -2253,8 +2250,9 @@ fn trans_compare(cx: @block_ctxt, op: ast::binop, lhs: ValueRef,
// Important to get types for both lhs and rhs, because one might be _|_
// and the other not.
fn trans_eager_binop(cx: @block_ctxt, op: ast::binop, lhs: ValueRef,
lhs_t: ty::t, rhs: ValueRef, rhs_t: ty::t) -> result {
lhs_t: ty::t, rhs: ValueRef, rhs_t: ty::t, dest: dest)
-> @block_ctxt {
if dest == ignore { ret cx; }
let is_float = false;
let intype = lhs_t;
if ty::type_is_bot(bcx_tcx(cx), intype) { intype = rhs_t; }
@ -2263,45 +2261,47 @@ fn trans_eager_binop(cx: @block_ctxt, op: ast::binop, lhs: ValueRef,
ty::ty_float. { is_float = true; }
_ { is_float = false; }
}
alt op {
if op == ast::add && ty::type_is_sequence(bcx_tcx(cx), intype) {
ret tvec::trans_add(cx, intype, lhs, rhs, dest);
}
let val = alt op {
ast::add. {
if ty::type_is_sequence(bcx_tcx(cx), intype) {
ret tvec::trans_add(cx, intype, lhs, rhs);
}
if is_float {
ret rslt(cx, FAdd(cx, lhs, rhs));
} else { ret rslt(cx, Add(cx, lhs, rhs)); }
if is_float { FAdd(cx, lhs, rhs) }
else { Add(cx, lhs, rhs) }
}
ast::sub. {
if is_float {
ret rslt(cx, FSub(cx, lhs, rhs));
} else { ret rslt(cx, Sub(cx, lhs, rhs)); }
if is_float { FSub(cx, lhs, rhs) }
else { Sub(cx, lhs, rhs) }
}
ast::mul. {
if is_float {
ret rslt(cx, FMul(cx, lhs, rhs));
} else { ret rslt(cx, Mul(cx, lhs, rhs)); }
if is_float { FMul(cx, lhs, rhs) }
else { Mul(cx, lhs, rhs) }
}
ast::div. {
if is_float { ret rslt(cx, FDiv(cx, lhs, rhs)); }
if ty::type_is_signed(bcx_tcx(cx), intype) {
ret rslt(cx, SDiv(cx, lhs, rhs));
} else { ret rslt(cx, UDiv(cx, lhs, rhs)); }
if is_float { FDiv(cx, lhs, rhs) }
else if ty::type_is_signed(bcx_tcx(cx), intype) {
SDiv(cx, lhs, rhs)
} else { UDiv(cx, lhs, rhs) }
}
ast::rem. {
if is_float { ret rslt(cx, FRem(cx, lhs, rhs)); }
if ty::type_is_signed(bcx_tcx(cx), intype) {
ret rslt(cx, SRem(cx, lhs, rhs));
} else { ret rslt(cx, URem(cx, lhs, rhs)); }
if is_float { FRem(cx, lhs, rhs) }
else if ty::type_is_signed(bcx_tcx(cx), intype) {
SRem(cx, lhs, rhs)
} else { URem(cx, lhs, rhs) }
}
ast::bitor. { ret rslt(cx, Or(cx, lhs, rhs)); }
ast::bitand. { ret rslt(cx, And(cx, lhs, rhs)); }
ast::bitxor. { ret rslt(cx, Xor(cx, lhs, rhs)); }
ast::lsl. { ret rslt(cx, Shl(cx, lhs, rhs)); }
ast::lsr. { ret rslt(cx, LShr(cx, lhs, rhs)); }
ast::asr. { ret rslt(cx, AShr(cx, lhs, rhs)); }
_ { ret trans_compare(cx, op, lhs, lhs_t, rhs, rhs_t); }
}
ast::bitor. { Or(cx, lhs, rhs) }
ast::bitand. { And(cx, lhs, rhs) }
ast::bitxor. { Xor(cx, lhs, rhs) }
ast::lsl. { Shl(cx, lhs, rhs) }
ast::lsr. { LShr(cx, lhs, rhs) }
ast::asr. { AShr(cx, lhs, rhs) }
_ {
let cmpr = trans_compare(cx, op, lhs, lhs_t, rhs, rhs_t);
cx = cmpr.bcx;
cmpr.val
}
};
ret store_in_dest(cx, val, dest);
}
fn trans_assign_op(bcx: @block_ctxt, op: ast::binop, dst: @ast::expr,
@ -2334,11 +2334,8 @@ fn trans_assign_op(bcx: @block_ctxt, op: ast::binop, dst: @ast::expr,
}
}
let lhs_val = load_if_immediate(rhs_res.bcx, lhs_res.val, t);
let v = trans_eager_binop(rhs_res.bcx, op, lhs_val, t, rhs_res.val, t);
// FIXME: calculate copy init-ness in typestate.
// This is always a temporary, so can always be safely moved
ret move_val(v.bcx, DROP_EXISTING, lhs_res.val,
lval_val(v.bcx, v.val), t);
ret trans_eager_binop(rhs_res.bcx, op, lhs_val, t, rhs_res.val, t,
overwrite(lhs_res.val, t));
}
fn autoderef(cx: @block_ctxt, v: ValueRef, t: ty::t) -> result_t {
@ -2390,84 +2387,55 @@ fn autoderef(cx: @block_ctxt, v: ValueRef, t: ty::t) -> result_t {
ret {bcx: cx, val: v1, ty: t1};
}
fn trans_binary(cx: @block_ctxt, op: ast::binop, a: @ast::expr, b: @ast::expr)
-> result {
fn trans_lazy_binop(bcx: @block_ctxt, op: ast::binop, a: @ast::expr,
b: @ast::expr, dest: dest) -> @block_ctxt {
let is_and = alt op { ast::and. { true } ast::or. { false } };
let lhs_res = trans_expr(bcx, a);
if lhs_res.bcx.unreachable { ret lhs_res.bcx; }
let rhs_cx = new_scope_block_ctxt(lhs_res.bcx, "rhs");
let rhs_res = trans_expr(rhs_cx, b);
let lhs_past_cx = new_scope_block_ctxt(lhs_res.bcx, "lhs");
// The following line ensures that any cleanups for rhs
// are done within the block for rhs. This is necessary
// because and/or are lazy. So the rhs may never execute,
// and the cleanups can't be pushed into later code.
let rhs_bcx = trans_block_cleanups(rhs_res.bcx, rhs_cx);
if is_and {
CondBr(lhs_res.bcx, lhs_res.val, rhs_cx.llbb, lhs_past_cx.llbb);
} else {
CondBr(lhs_res.bcx, lhs_res.val, lhs_past_cx.llbb, rhs_cx.llbb);
}
let join_cx = new_sub_block_ctxt(bcx, "join");
Br(lhs_past_cx, join_cx.llbb);
if rhs_bcx.unreachable {
ret store_in_dest(join_cx, C_bool(!is_and), dest);
}
Br(rhs_bcx, join_cx.llbb);
let phi = Phi(join_cx, T_bool(), [C_bool(!is_and), rhs_res.val],
[lhs_past_cx.llbb, rhs_bcx.llbb]);
ret store_in_dest(join_cx, phi, dest);
}
fn trans_binary(cx: @block_ctxt, op: ast::binop, a: @ast::expr, b: @ast::expr,
dest: dest) -> @block_ctxt {
// First couple cases are lazy:
alt op {
ast::and. {
// Lazy-eval and
let lhs_res = trans_expr(cx, a);
let rhs_cx = new_scope_block_ctxt(lhs_res.bcx, "rhs");
let rhs_res = trans_expr(rhs_cx, b);
let lhs_false_cx = new_scope_block_ctxt(lhs_res.bcx, "lhs false");
let lhs_false_res = rslt(lhs_false_cx, C_bool(false));
// The following line ensures that any cleanups for rhs
// are done within the block for rhs. This is necessary
// because and/or are lazy. So the rhs may never execute,
// and the cleanups can't be pushed into later code.
let rhs_bcx = trans_block_cleanups(rhs_res.bcx, rhs_cx);
CondBr(lhs_res.bcx, lhs_res.val, rhs_cx.llbb, lhs_false_cx.llbb);
ret join_results(cx, T_bool(),
[lhs_false_res, {bcx: rhs_bcx, val: rhs_res.val}]);
}
ast::or. {
// Lazy-eval or
let lhs_res = trans_expr(cx, a);
let rhs_cx = new_scope_block_ctxt(lhs_res.bcx, "rhs");
let rhs_res = trans_expr(rhs_cx, b);
let lhs_true_cx = new_scope_block_ctxt(lhs_res.bcx, "lhs true");
let lhs_true_res = rslt(lhs_true_cx, C_bool(true));
// see the and case for an explanation
let rhs_bcx = trans_block_cleanups(rhs_res.bcx, rhs_cx);
CondBr(lhs_res.bcx, lhs_res.val, lhs_true_cx.llbb, rhs_cx.llbb);
ret join_results(cx, T_bool(),
[lhs_true_res, {bcx: rhs_bcx, val: rhs_res.val}]);
ast::and. | ast::or. {
ret trans_lazy_binop(cx, op, a, b, dest);
}
_ {
// Remaining cases are eager:
let lhs = trans_expr(cx, a);
let rhs = trans_expr(lhs.bcx, b);
ret trans_eager_binop(rhs.bcx, op, lhs.val,
ty::expr_ty(bcx_tcx(cx), a), rhs.val,
ty::expr_ty(bcx_tcx(cx), b));
ty::expr_ty(bcx_tcx(cx), b), dest);
}
}
}
fn join_results(parent_cx: @block_ctxt, t: TypeRef, ins: [result]) -> result {
let live: [result] = [];
let vals: [ValueRef] = [];
let bbs: [BasicBlockRef] = [];
for r: result in ins {
if !r.bcx.unreachable {
live += [r];
vals += [r.val];
bbs += [r.bcx.llbb];
}
}
alt std::vec::len::<result>(live) {
0u {
// No incoming edges are live, so we're in dead-code-land.
// Arbitrarily pick the first dead edge, since the caller
// is just going to propagate it outward.
assert (std::vec::len::<result>(ins) >= 1u);
ret ins[0];
}
_ {/* fall through */ }
}
// We have >1 incoming edges. Make a join block and br+phi them into it.
let join_cx = new_sub_block_ctxt(parent_cx, "join");
for r: result in live { Br(r.bcx, join_cx.llbb); }
let phi = Phi(join_cx, t, vals, bbs);
ret rslt(join_cx, phi);
}
// FIXME remove once all uses have been converted to join_returns
fn join_branches(parent_cx: @block_ctxt, ins: [result]) -> @block_ctxt {
let out = new_sub_block_ctxt(parent_cx, "join");
@ -2483,6 +2451,7 @@ tag dest {
by_val(@mutable ValueRef);
by_ref(@mutable ValueRef);
save_in(ValueRef);
overwrite(ValueRef, ty::t);
ignore;
}
@ -2529,6 +2498,20 @@ fn join_returns(parent_cx: @block_ctxt, in_cxs: [@block_ctxt],
ret out;
}
// Used to put an immediate value in a dest
fn store_in_dest(bcx: @block_ctxt, val: ValueRef, dest: dest) -> @block_ctxt {
alt dest {
ignore. {}
by_val(cell) { *cell = val; }
save_in(addr) { Store(bcx, val, addr); }
overwrite(addr, tp) {
bcx = drop_ty(bcx, addr, tp);
Store(bcx, val, addr);
}
}
ret bcx;
}
// Wrapper through which legacy non-DPS code can use DPS functions
fn dps_to_result(bcx: @block_ctxt,
work: block(@block_ctxt, dest) -> @block_ctxt,
@ -4135,7 +4118,6 @@ fn trans_rec(bcx: @block_ctxt, fields: [ast::field],
fn trans_expr(cx: @block_ctxt, e: @ast::expr) -> result {
// Fixme Fill in cx.sp
alt e.node {
ast::expr_binary(op, x, y) { ret trans_binary(cx, op, x, y); }
ast::expr_fn(f) {
let ccx = bcx_ccx(cx);
let fty = node_id_type(ccx, e.id);
@ -4267,6 +4249,7 @@ fn trans_expr_dps(bcx: @block_ctxt, e: @ast::expr, dest: dest)
ast::expr_tup(args) { ret trans_tup(bcx, args, e.id, dest); }
ast::expr_lit(lit) { ret trans_lit(bcx, *lit, dest); }
ast::expr_vec(args, _) { ret tvec::trans_vec(bcx, args, e.id, dest); }
ast::expr_binary(op, x, y) { ret trans_binary(bcx, op, x, y, dest); }
ast::expr_break. {
assert dest == ignore;
@ -4399,6 +4382,9 @@ fn trans_expr_dps(bcx: @block_ctxt, e: @ast::expr, dest: dest)
*cell = val;
}
save_in(loc) { bcx = move_val_if_temp(bcx, INIT, loc, lv, ty); }
overwrite(loc, _) {
bcx = move_val_if_temp(bcx, DROP_EXISTING, loc, lv, ty);
}
ignore. {}
}
ret bcx;

View file

@ -36,9 +36,10 @@ fn trans_opt(bcx: @block_ctxt, o: opt) -> result {
lit(l) {
alt l.node {
ast::lit_str(s) {
let {bcx, val: dst} =
trans::alloc_ty(bcx, ty::mk_str(bcx_tcx(bcx)));
let strty = ty::mk_str(bcx_tcx(bcx));
let {bcx, val: dst} = trans::alloc_ty(bcx, strty);
bcx = trans_vec::trans_str(bcx, s, trans::save_in(dst));
add_clean_temp(bcx, dst, strty);
ret rslt(bcx, dst);
}
_ {

View file

@ -100,9 +100,14 @@ fn make_drop_glue(bcx: @block_ctxt, vptrptr: ValueRef, vec_ty: ty::t) ->
ret next_cx;
}
// FIXME handle dest == ignore
fn trans_vec(bcx: @block_ctxt, args: [@ast::expr], id: ast::node_id,
dest: dest) -> @block_ctxt {
if dest == trans::ignore {
for arg in args {
bcx = trans::trans_expr_dps(bcx, arg, trans::ignore);
}
ret bcx;
}
let vec_ty = node_id_type(bcx_ccx(bcx), id);
let {bcx: bcx,
val: vptrptr,
@ -113,17 +118,20 @@ fn trans_vec(bcx: @block_ctxt, args: [@ast::expr], id: ast::node_id,
// Store the individual elements.
let dataptr = get_dataptr(bcx, vptrptr, llunitty);
let i = 0u;
add_clean_temp_mem(bcx, vptrptr, vec_ty);
let i = 0u, temp_cleanups = [vptrptr];
for e in args {
let lv = trans_lval(bcx, e);
bcx = lv.bcx;
let lleltptr =
if ty::type_has_dynamic_size(bcx_tcx(bcx), unit_ty) {
InBoundsGEP(bcx, dataptr, [Mul(bcx, C_uint(i), llunitsz)])
} else { InBoundsGEP(bcx, dataptr, [C_uint(i)]) };
let lleltptr = if ty::type_has_dynamic_size(bcx_tcx(bcx), unit_ty) {
InBoundsGEP(bcx, dataptr, [Mul(bcx, C_uint(i), llunitsz)])
} else { InBoundsGEP(bcx, dataptr, [C_uint(i)]) };
bcx = move_val_if_temp(bcx, INIT, lleltptr, lv, unit_ty);
add_clean_temp_mem(bcx, lleltptr, unit_ty);
temp_cleanups += [lleltptr];
i += 1u;
}
for clean in temp_cleanups { revoke_clean(bcx, clean); }
ret bcx;
}
fn trans_str(bcx: @block_ctxt, s: str, dest: dest) -> @block_ctxt {
@ -213,12 +221,11 @@ fn trans_append_literal(bcx: @block_ctxt, vptrptr: ValueRef, vec_ty: ty::t,
}
fn trans_add(bcx: @block_ctxt, vec_ty: ty::t, lhsptr: ValueRef,
rhsptr: ValueRef) -> result {
let strings =
alt ty::struct(bcx_tcx(bcx), vec_ty) {
ty::ty_str. { true }
ty::ty_vec(_) { false }
};
rhsptr: ValueRef, dest: dest) -> @block_ctxt {
let strings = alt ty::struct(bcx_tcx(bcx), vec_ty) {
ty::ty_str. { true }
ty::ty_vec(_) { false }
};
let unit_ty = ty::sequence_element_type(bcx_tcx(bcx), vec_ty);
let llunitty = type_of_or_i8(bcx, unit_ty);
let {bcx: bcx, val: llunitsz} = size_of(bcx, unit_ty);
@ -229,9 +236,8 @@ fn trans_add(bcx: @block_ctxt, vec_ty: ty::t, lhsptr: ValueRef,
let new_fill = Add(bcx, lhs_fill, rhs_fill);
let {bcx: bcx, val: new_vec_ptr} = alloc_raw(bcx, new_fill, new_fill);
new_vec_ptr = PointerCast(bcx, new_vec_ptr, T_ptr(T_vec(llunitty)));
let {bcx: bcx, val: new_vec_ptr_ptr} = alloc_ty(bcx, vec_ty);
let new_vec_ptr_ptr = alt dest { trans::save_in(a) { a } };
Store(bcx, new_vec_ptr, new_vec_ptr_ptr);
add_clean_temp(bcx, new_vec_ptr_ptr, vec_ty);
let write_ptr_ptr =
do_spill_noroot(bcx, get_dataptr(bcx, new_vec_ptr_ptr, llunitty));
@ -252,8 +258,7 @@ fn trans_add(bcx: @block_ctxt, vec_ty: ty::t, lhsptr: ValueRef,
}(_, _, _, write_ptr_ptr, unit_ty, llunitsz);
let bcx = iter_vec_raw(bcx, lhsptr, vec_ty, lhs_fill, copy_fn);
let bcx = iter_vec_raw(bcx, rhsptr, vec_ty, rhs_fill, copy_fn);
ret rslt(bcx, new_vec_ptr_ptr);
ret iter_vec_raw(bcx, rhsptr, vec_ty, rhs_fill, copy_fn);
}
type val_and_ty_fn = fn(@block_ctxt, ValueRef, ty::t) -> result;