Skip to content

Commit 8c0918a

Browse files
committed
Construct records and tuples in-place
Issue #667 Now, {a: {b: 10, c: 20}, d: @30} will simply write the values in the right places, rather than creating intermediary records and then memmoving them. Cuts about a megabyte off the unoptimized compiler size.
1 parent 5837975 commit 8c0918a

File tree

2 files changed

+53
-58
lines changed

2 files changed

+53
-58
lines changed

src/comp/middle/trans.rs

Lines changed: 48 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -4002,32 +4002,30 @@ fn trans_landing_pad(bcx: @block_ctxt,
40024002
fn trans_tup(bcx: @block_ctxt, elts: [@ast::expr], id: ast::node_id,
40034003
dest: dest) -> @block_ctxt {
40044004
let t = node_id_type(bcx.fcx.lcx.ccx, id);
4005-
let dst = alt dest { save_in(addr) { addr } };
4006-
4007-
// Like trans_rec, we'll collect the fields of the tuple then build it, so
4008-
// that if we fail in between we don't have to deal with cleaning up a
4009-
// partial tuple
4010-
let tupfields = [], i = 0;
4005+
let temp_cleanups = [], i = 0;
40114006
for e in elts {
4012-
let e_ty = ty::expr_ty(bcx_tcx(bcx), e);
4013-
let src = trans_lval(bcx, e);
4014-
let dst_res = GEP_tup_like_1(src.bcx, t, dst, [0, i]);
4015-
bcx = dst_res.bcx;
4016-
tupfields += [(dst_res.val, src, e_ty)];
4007+
alt dest {
4008+
save_in(addr) {
4009+
let dst = GEP_tup_like_1(bcx, t, addr, [0, i]);
4010+
let e_ty = ty::expr_ty(bcx_tcx(bcx), e);
4011+
bcx = trans_expr_save_in(dst.bcx, e, dst.val);
4012+
add_clean_temp_mem(bcx, dst.val, e_ty);
4013+
temp_cleanups += [dst.val];
4014+
}
4015+
ignore. {
4016+
bcx = trans_expr_dps(bcx, e, ignore);
4017+
}
4018+
}
40174019
i += 1;
40184020
}
4019-
// Fill in the tuple fields
4020-
for (dst, src, t) in tupfields {
4021-
bcx = move_val_if_temp(bcx, INIT, dst, src, t);
4022-
}
4021+
for cleanup in temp_cleanups { revoke_clean(bcx, cleanup); }
40234022
ret bcx;
40244023
}
40254024

40264025
fn trans_rec(bcx: @block_ctxt, fields: [ast::field],
40274026
base: option::t<@ast::expr>, id: ast::node_id,
40284027
dest: dest) -> @block_ctxt {
40294028
let t = node_id_type(bcx_ccx(bcx), id);
4030-
let dst = alt dest { save_in(addr) { addr } };
40314029

40324030
let base_val = alt base {
40334031
some(bexp) {
@@ -4038,58 +4036,50 @@ fn trans_rec(bcx: @block_ctxt, fields: [ast::field],
40384036
none. { C_nil() }
40394037
};
40404038

4041-
tag fieldsrc {
4042-
provided(lval_result);
4043-
inherited(ValueRef);
4044-
}
4045-
type fieldval = {
4046-
dst: ValueRef,
4047-
src: fieldsrc,
4048-
ty: ty::t
4049-
};
4050-
40514039
let ty_fields = alt ty::struct(bcx_tcx(bcx), t) { ty::ty_rec(f) { f } };
4052-
let fieldvals = [], i = 0;
4053-
// We build the record in two stages so that we don't have to clean up a
4054-
// partial record if we fail: first collect all the values, then construct
4055-
// the record.
4040+
let temp_cleanups = [], i = 0;
40564041
for tf in ty_fields {
4057-
let {bcx: a_bcx, val: addr} = GEP_tup_like_1(bcx, t, dst, [0, i]);
4058-
bcx = a_bcx;
4059-
// FIXME make this happen in a single pass, again, somehow make the
4060-
// dps helpers tie the cleanups together in the right way (we do not
4061-
// want to create intermediates for these and then move them again)
4062-
fn test(n: str, f: ast::field) -> bool { str::eq(f.node.ident, n) }
4042+
let fdest = alt dest {
4043+
save_in(addr) {
4044+
let gep = GEP_tup_like_1(bcx, t, addr, [0, i]);
4045+
bcx = gep.bcx;
4046+
some(gep.val)
4047+
}
4048+
ignore. { none }
4049+
};
40634050
// FIXME make this {|f| str::eq(f.node.ident, tf.ident)} again when
40644051
// bug #913 is fixed
4065-
let s = alt vec::find(bind test(tf.ident, _), fields) {
4066-
some(f) {
4067-
let lv = trans_lval(bcx, f.node.expr);
4068-
bcx = lv.bcx;
4069-
provided(lv)
4052+
fn test(n: str, f: ast::field) -> bool { str::eq(f.node.ident, n) }
4053+
alt vec::find(bind test(tf.ident, _), fields) {
4054+
some(f) {
4055+
alt fdest {
4056+
some(x) { bcx = trans_expr_save_in(bcx, f.node.expr, x); }
4057+
none. { bcx = trans_expr_dps(bcx, f.node.expr, ignore); }
40704058
}
4071-
none. {
4072-
let src_res = GEP_tup_like_1(bcx, t, base_val, [0, i]);
4073-
bcx = src_res.bcx;
4074-
inherited(src_res.val)
4059+
}
4060+
none. {
4061+
alt fdest {
4062+
some(addr) {
4063+
let gep = GEP_tup_like_1(bcx, t, base_val, [0, i]);
4064+
let val = load_if_immediate(gep.bcx, gep.val, tf.mt.ty);
4065+
bcx = copy_val(gep.bcx, INIT, addr, val, tf.mt.ty);
4066+
}
4067+
none. {}
40754068
}
4076-
};
4077-
fieldvals += [{dst: addr, src: s, ty: tf.mt.ty}];
4078-
i += 1;
4079-
}
4080-
// Now build the record
4081-
for fieldval in fieldvals {
4082-
alt fieldval.src {
4083-
provided(lv) {
4084-
bcx = move_val_if_temp(bcx, INIT, fieldval.dst,
4085-
lv, fieldval.ty);
40864069
}
4087-
inherited(val) {
4088-
let val = load_if_immediate(bcx, val, fieldval.ty);
4089-
bcx = copy_val(bcx, INIT, fieldval.dst, val, fieldval.ty);
4070+
}
4071+
alt fdest {
4072+
some(addr) {
4073+
add_clean_temp_mem(bcx, addr, tf.mt.ty);
4074+
temp_cleanups += [addr];
40904075
}
4076+
none. {}
40914077
}
4078+
i += 1;
40924079
}
4080+
// Now revoke the cleanups as we pass responsibility for the data
4081+
// structure on to the caller
4082+
for cleanup in temp_cleanups { revoke_clean(bcx, cleanup); }
40934083
ret bcx;
40944084
}
40954085

src/comp/middle/trans_common.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,11 @@ fn add_clean_temp(cx: @block_ctxt, val: ValueRef, ty: ty::t) {
283283
[clean_temp(val, bind spill_and_drop(_, val, ty))];
284284
scope_cx.lpad_dirty = true;
285285
}
286+
fn add_clean_temp_mem(cx: @block_ctxt, val: ValueRef, ty: ty::t) {
287+
let scope_cx = find_scope_cx(cx);
288+
scope_cx.cleanups += [clean_temp(val, bind drop_ty(_, val, ty))];
289+
scope_cx.lpad_dirty = true;
290+
}
286291

287292
// Note that this only works for temporaries. We should, at some point, move
288293
// to a system where we can also cancel the cleanup on local variables, but

0 commit comments

Comments
 (0)