Optimize += [x] into a simple push operation

This is a preparation for making vectors always-on-the-heap again,
which would cause way too much malloc traffic for this idiom. I will
add an efficient std::vec::push in the future, and migrate += [x] to
that instead.

Reduces compiler code size by 3%
This commit is contained in:
Marijn Haverbeke 2011-08-24 13:53:34 +02:00
parent bead045f27
commit e58c48bdda
5 changed files with 82 additions and 14 deletions

View File

@ -43,6 +43,7 @@ type upcalls =
ivec_spill: ValueRef,
ivec_resize_shared: ValueRef,
ivec_spill_shared: ValueRef,
ivec_push: ValueRef,
cmp_type: ValueRef,
log_type: ValueRef,
dynastack_mark: ValueRef,
@ -101,6 +102,9 @@ fn declare_upcalls(_tn: type_names, tydesc_type: TypeRef,
ivec_spill_shared:
d("ivec_spill_shared", [T_ptr(T_opaque_ivec()), T_int()],
T_void()),
ivec_push:
d("ivec_push", [T_ptr(T_opaque_ivec()), T_ptr(tydesc_type),
T_ptr(T_i8())], T_void()),
cmp_type:
dr("cmp_type",
[T_ptr(T_i1()), taskptr_type, T_ptr(tydesc_type),

View File

@ -4351,16 +4351,32 @@ fn trans_expr_out(cx: &@block_ctxt, e: &@ast::expr, output: out_method) ->
ret rslt(bcx, C_nil());
}
ast::expr_assign_op(op, dst, src) {
let t = ty::expr_ty(bcx_tcx(cx), src);
let tcx = bcx_tcx(cx);
let t = ty::expr_ty(tcx, src);
let lhs_res = trans_lval(cx, dst);
assert (lhs_res.is_mem);
// FIXME Fill in lhs_res.res.bcx.sp
// Special case for `+= [x]`
alt ty::struct(tcx, t) {
ty::ty_vec(_) {
alt src.node {
ast::expr_vec(args, _) {
let bcx = ivec::trans_append_literal
(lhs_res.res.bcx, lhs_res.res.val, t, args);
ret rslt(bcx, C_nil());
}
_ {}
}
}
_ {}
}
// FIXME Fill in lhs_res.res.bcx.sp
let rhs_res = trans_expr(lhs_res.res.bcx, src);
if ty::type_is_sequence(bcx_tcx(cx), t) {
if ty::type_is_sequence(tcx, t) {
alt op {
ast::add. {
if ty::sequence_is_interior(bcx_tcx(cx), t) {
if ty::sequence_is_interior(tcx, t) {
ret ivec::trans_append(rhs_res.bcx, t, lhs_res.res.val,
rhs_res.val);
}

View File

@ -11,9 +11,6 @@ import trans::{call_memmove, trans_shared_malloc, llsize_of,
new_sub_block_ctxt};
import trans_common::*;
export trans_ivec, get_len_and_data, duplicate_heap_part, trans_add,
trans_append, alloc_with_heap;
fn alloc_with_heap(bcx: @block_ctxt, typ: &ty::t, vecsz: uint) ->
{bcx: @block_ctxt,
unit_ty: ty::t,
@ -342,15 +339,13 @@ fn reserve_space(cx: &@block_ctxt, llunitty: TypeRef, v: ValueRef,
stack_no_spill_cx.llbb, stack_spill_cx.llbb]);
ret rslt(next_cx, data_ptr);
}
fn trans_append(cx: &@block_ctxt, t: ty::t, orig_lhs: ValueRef,
orig_rhs: ValueRef) -> result {
fn trans_append(cx: &@block_ctxt, t: ty::t, lhs: ValueRef,
rhs: ValueRef) -> result {
// Cast to opaque interior vector types if necessary.
let lhs;
let rhs;
if ty::type_has_dynamic_size(bcx_tcx(cx), t) {
lhs = cx.build.PointerCast(orig_lhs, T_ptr(T_opaque_ivec()));
rhs = cx.build.PointerCast(orig_rhs, T_ptr(T_opaque_ivec()));
} else { lhs = orig_lhs; rhs = orig_rhs; }
lhs = cx.build.PointerCast(lhs, T_ptr(T_opaque_ivec()));
rhs = cx.build.PointerCast(rhs, T_ptr(T_opaque_ivec()));
}
let unit_ty = ty::sequence_element_type(bcx_tcx(cx), t);
let llunitty = type_of_or_i8(cx, unit_ty);
@ -448,6 +443,24 @@ fn trans_append(cx: &@block_ctxt, t: ty::t, orig_lhs: ValueRef,
ret rslt(next_cx, C_nil());
}
fn trans_append_literal(bcx: &@block_ctxt, v: ValueRef, vec_ty: ty::t,
vals: &[@ast::expr]) -> @block_ctxt {
let elt_ty = ty::sequence_element_type(bcx_tcx(bcx), vec_ty);
let ti = none;
let {bcx, val: td} = get_tydesc(bcx, elt_ty, false, ti).result;
trans::lazily_emit_all_tydesc_glue(bcx, ti);
let opaque_v = bcx.build.PointerCast(v, T_ptr(T_opaque_ivec()));
for val in vals {
let {bcx: e_bcx, val: elt} = trans::trans_expr(bcx, val);
bcx = e_bcx;
let spilled = trans::spill_if_immediate(bcx, elt, elt_ty);
bcx.build.Call(bcx_ccx(bcx).upcalls.ivec_push,
[bcx.fcx.lltaskptr, opaque_v, td,
bcx.build.PointerCast(spilled, T_ptr(T_i8()))]);
}
ret bcx;
}
type alloc_result =
{bcx: @block_ctxt,
llptr: ValueRef,
@ -756,3 +769,13 @@ fn duplicate_heap_part(cx: &@block_ctxt, orig_vptr: ValueRef,
ret rslt(next_cx, C_nil());
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//

View File

@ -394,6 +394,30 @@ upcall_ivec_spill_shared(rust_task *task,
v->payload.ptr = heap_part;
}
extern "C" CDECL void
upcall_ivec_push(rust_task* task, rust_ivec* v, type_desc* elt_ty, void* x) {
LOG_UPCALL_ENTRY(task);
bool is_interior = v->fill || !v->payload.ptr;
size_t sz = elt_ty->size;
size_t old_fill = is_interior ? v->fill : v->payload.ptr->fill;
size_t new_sz = sz + old_fill;
if (new_sz > v->alloc) {
if (is_interior) {
upcall_ivec_spill_shared(task, v, new_sz);
is_interior = false;
} else {
upcall_ivec_resize_shared(task, v, new_sz);
}
} else {
if (is_interior) v->fill = new_sz;
else v->payload.ptr->fill = new_sz;
}
uint8_t* dataptr = is_interior ? &v->payload.data[0]
: &v->payload.ptr->data[0];
copy_elements(task, elt_ty, dataptr + old_fill, x, sz);
}
/**
* Returns a token that can be used to deallocate all of the allocated space
* space in the dynamic stack.

View File

@ -89,6 +89,7 @@ upcall_get_type_desc
upcall_grow_task
upcall_ivec_resize_shared
upcall_ivec_spill_shared
upcall_ivec_push
upcall_kill
upcall_log_double
upcall_log_float