Factor vector-allocation code, always allocate space for at least 4 elts

(This prevents the first few reallocs when growing a vector.)
This commit is contained in:
Marijn Haverbeke 2011-08-29 22:30:18 +02:00
parent 5483b910d6
commit eb4661fc52

View file

@ -31,33 +31,39 @@ fn pointer_add(bcx: &@block_ctxt, ptr: ValueRef, bytes: ValueRef)
ret PointerCast(bcx, InBoundsGEP(bcx, bptr, [bytes]), old_ty);
}
// FIXME factor out a scaling version wrapping a non-scaling version
fn alloc(bcx: &@block_ctxt, vec_ty: &ty::t, vecsz: ValueRef, is_scaled: bool)
-> {bcx: @block_ctxt,
val: ValueRef,
unit_ty: ty::t,
llunitsz: ValueRef,
llunitty: TypeRef} {
fn alloc_raw(bcx: &@block_ctxt, fill: ValueRef, alloc: ValueRef) -> result {
let llvecty = T_opaque_ivec();
let vecsize = Add(bcx, alloc, llsize_of(llvecty));
let {bcx, val: vecptr} =
trans_shared_malloc(bcx, T_ptr(llvecty), vecsize);
Store(bcx, fill, InBoundsGEP
(bcx, vecptr, [C_int(0), C_uint(abi::ivec_elt_fill)]));
Store(bcx, alloc, InBoundsGEP
(bcx, vecptr, [C_int(0), C_uint(abi::ivec_elt_alloc)]));
ret {bcx: bcx, val: vecptr};
}
type alloc_result = {bcx: @block_ctxt,
val: ValueRef,
unit_ty: ty::t,
llunitsz: ValueRef,
llunitty: TypeRef};
fn alloc(bcx: &@block_ctxt, vec_ty: &ty::t, elts: uint) -> alloc_result {
let unit_ty = ty::sequence_element_type(bcx_tcx(bcx), vec_ty);
let llunitty = type_of_or_i8(bcx, unit_ty);
let llvecty = T_ivec(llunitty);
let {bcx, val: unit_sz} = size_of(bcx, unit_ty);
let fill = if is_scaled { vecsz }
else { Mul(bcx, vecsz, unit_sz) };
let vecsize = Add(bcx, fill, llsize_of(llvecty));
let {bcx, val: vecptr} =
trans_shared_malloc(bcx, T_ptr(llvecty), vecsize);
add_clean_temp(bcx, vecptr, vec_ty);
Store(bcx, fill, InBoundsGEP
(bcx, vecptr, [C_int(0), C_uint(abi::ivec_elt_fill)]));
Store(bcx, fill, InBoundsGEP
(bcx, vecptr, [C_int(0), C_uint(abi::ivec_elt_alloc)]));
ret {bcx: bcx, val: vecptr,
unit_ty: unit_ty, llunitsz: unit_sz, llunitty: llunitty};
let fill = Mul(bcx, C_uint(elts), unit_sz);
let alloc = if elts < 4u { Mul(bcx, C_int(4), unit_sz) } else { fill };
let {bcx, val: vptr} = alloc_raw(bcx, fill, alloc);
let vptr = PointerCast(bcx, vptr, T_ptr(llvecty));
add_clean_temp(bcx, vptr, vec_ty);
ret {bcx: bcx, val: vptr, unit_ty: unit_ty,
llunitsz: unit_sz, llunitty: llunitty};
}
fn duplicate(bcx: &@block_ctxt, vptrptr: ValueRef) -> @block_ctxt {
let vptr = Load(bcx, vptrptr);
let fill = get_fill(bcx, vptr);
@ -89,7 +95,7 @@ fn trans_ivec(bcx: &@block_ctxt, args: &[@ast::expr],
id: ast::node_id) -> result {
let vec_ty = node_id_type(bcx_ccx(bcx), id);
let {bcx, val: vptr, llunitsz, unit_ty, llunitty} =
alloc(bcx, vec_ty, C_uint(vec::len(args)), false);
alloc(bcx, vec_ty, vec::len(args));
// Store the individual elements.
let dataptr = get_dataptr(bcx, vptr, llunitty);
@ -110,7 +116,7 @@ fn trans_ivec(bcx: &@block_ctxt, args: &[@ast::expr],
fn trans_istr(bcx: &@block_ctxt, s: istr) -> result {
let veclen = std::istr::byte_len(s) + 1u; // +1 for \0
let {bcx, val: sptr, _} =
alloc(bcx, ty::mk_istr(bcx_tcx(bcx)), C_uint(veclen), false);
alloc(bcx, ty::mk_istr(bcx_tcx(bcx)), veclen);
let llcstr = C_cstr(bcx_ccx(bcx), s);
let bcx = call_memmove(bcx, get_dataptr(bcx, sptr, T_i8()),
@ -194,12 +200,17 @@ fn trans_add(bcx: &@block_ctxt, vec_ty: ty::t, lhs: ValueRef,
ty::ty_istr. { 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, val: llunitsz} = size_of(bcx, unit_ty);
let lhs_fill = get_fill(bcx, lhs);
if strings { lhs_fill = Sub(bcx, lhs_fill, C_int(1)); }
let rhs_fill = get_fill(bcx, rhs);
let new_fill = Add(bcx, lhs_fill, rhs_fill);
let {bcx, val: new_vec, unit_ty, llunitsz, llunitty} =
alloc(bcx, vec_ty, new_fill, true);
let {bcx, val: new_vec} = alloc_raw(bcx, new_fill, new_fill);
let new_vec = PointerCast(bcx, new_vec, T_ptr(T_ivec(llunitty)));
add_clean_temp(bcx, new_vec, vec_ty);
let write_ptr_ptr = do_spill(bcx, get_dataptr(bcx, new_vec, llunitty));
let copy_fn = bind fn(bcx: &@block_ctxt, addr: ValueRef, _ty: ty::t,