From e58c48bddae60e21dc8958407dadf6d187b78ea9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 24 Aug 2011 13:53:34 +0200 Subject: [PATCH] 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% --- src/comp/back/upcall.rs | 4 ++++ src/comp/middle/trans.rs | 24 +++++++++++++++---- src/comp/middle/trans_ivec.rs | 43 +++++++++++++++++++++++++++-------- src/rt/rust_upcall.cpp | 24 +++++++++++++++++++ src/rt/rustrt.def.in | 1 + 5 files changed, 82 insertions(+), 14 deletions(-) diff --git a/src/comp/back/upcall.rs b/src/comp/back/upcall.rs index eb1741767adf..3ff3371c3b0d 100644 --- a/src/comp/back/upcall.rs +++ b/src/comp/back/upcall.rs @@ -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), diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 35390bc1b92c..8899f207a660 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -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); } diff --git a/src/comp/middle/trans_ivec.rs b/src/comp/middle/trans_ivec.rs index b2189a92637d..8c15d3b023be 100644 --- a/src/comp/middle/trans_ivec.rs +++ b/src/comp/middle/trans_ivec.rs @@ -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: +// diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index 622baad32c9f..174855cac23a 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -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. diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 58aa681f6330..a3ecebf22a97 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -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