2011-08-22 13:48:00 -05:00
|
|
|
import syntax::ast;
|
2012-01-30 23:00:57 -06:00
|
|
|
import driver::session::session;
|
2012-02-01 04:04:56 -06:00
|
|
|
import lib::llvm::{ValueRef, TypeRef};
|
2011-08-22 13:48:00 -05:00
|
|
|
import back::abi;
|
2012-03-23 08:45:47 -05:00
|
|
|
import base::{call_memmove, shared_malloc,
|
2012-01-19 12:21:42 -06:00
|
|
|
INIT, copy_val, load_if_immediate, get_tydesc,
|
2012-02-17 06:17:40 -06:00
|
|
|
sub_block, do_spill_noroot,
|
2012-03-22 15:44:20 -05:00
|
|
|
dest, bcx_icx};
|
2012-04-09 19:32:49 -05:00
|
|
|
import syntax::codemap::span;
|
2012-03-12 04:05:15 -05:00
|
|
|
import shape::llsize_of;
|
2012-01-27 06:17:06 -06:00
|
|
|
import build::*;
|
|
|
|
import common::*;
|
2011-08-22 13:48:00 -05:00
|
|
|
|
2012-02-17 06:17:40 -06:00
|
|
|
fn get_fill(bcx: block, vptr: ValueRef) -> ValueRef {
|
2012-03-22 15:44:20 -05:00
|
|
|
let _icx = bcx.insn_ctxt("tvec::get_fill");
|
2011-10-26 00:23:28 -05:00
|
|
|
Load(bcx, GEPi(bcx, vptr, [0, abi::vec_elt_fill]))
|
2011-08-25 03:18:02 -05:00
|
|
|
}
|
2012-03-22 10:02:34 -05:00
|
|
|
fn set_fill(bcx: block, vptr: ValueRef, fill: ValueRef) {
|
|
|
|
Store(bcx, fill, GEPi(bcx, vptr, [0, abi::vec_elt_fill]));
|
|
|
|
}
|
|
|
|
fn get_alloc(bcx: block, vptr: ValueRef) -> ValueRef {
|
|
|
|
Load(bcx, GEPi(bcx, vptr, [0, abi::vec_elt_alloc]))
|
|
|
|
}
|
2012-02-17 06:17:40 -06:00
|
|
|
fn get_dataptr(bcx: block, vptr: ValueRef, unit_ty: TypeRef)
|
2011-09-27 13:21:44 -05:00
|
|
|
-> ValueRef {
|
2012-03-22 15:44:20 -05:00
|
|
|
let _icx = bcx.insn_ctxt("tvec::get_dataptr");
|
2011-10-26 00:23:28 -05:00
|
|
|
let ptr = GEPi(bcx, vptr, [0, abi::vec_elt_elems]);
|
2011-08-25 03:18:02 -05:00
|
|
|
PointerCast(bcx, ptr, T_ptr(unit_ty))
|
|
|
|
}
|
2011-08-22 13:48:00 -05:00
|
|
|
|
2012-02-17 06:17:40 -06:00
|
|
|
fn pointer_add(bcx: block, ptr: ValueRef, bytes: ValueRef) -> ValueRef {
|
2012-03-22 15:44:20 -05:00
|
|
|
let _icx = bcx.insn_ctxt("tvec::pointer_add");
|
2011-08-25 03:18:02 -05:00
|
|
|
let old_ty = val_ty(ptr);
|
|
|
|
let bptr = PointerCast(bcx, ptr, T_ptr(T_i8()));
|
|
|
|
ret PointerCast(bcx, InBoundsGEP(bcx, bptr, [bytes]), old_ty);
|
|
|
|
}
|
2011-08-22 13:48:00 -05:00
|
|
|
|
2012-02-17 06:17:40 -06:00
|
|
|
fn alloc_raw(bcx: block, fill: ValueRef, alloc: ValueRef) -> result {
|
2012-03-22 15:44:20 -05:00
|
|
|
let _icx = bcx.insn_ctxt("tvec::alloc_raw");
|
2012-02-21 07:20:18 -06:00
|
|
|
let ccx = bcx.ccx();
|
2011-10-14 22:38:24 -05:00
|
|
|
let llvecty = ccx.opaque_vec_type;
|
|
|
|
let vecsize = Add(bcx, alloc, llsize_of(ccx, llvecty));
|
2012-03-23 08:45:47 -05:00
|
|
|
let vecptr = shared_malloc(bcx, T_ptr(llvecty), vecsize);
|
2011-10-26 00:23:28 -05:00
|
|
|
Store(bcx, fill, GEPi(bcx, vecptr, [0, abi::vec_elt_fill]));
|
|
|
|
Store(bcx, alloc, GEPi(bcx, vecptr, [0, abi::vec_elt_alloc]));
|
2011-08-29 15:30:18 -05:00
|
|
|
ret {bcx: bcx, val: vecptr};
|
|
|
|
}
|
|
|
|
|
2011-09-02 17:34:58 -05:00
|
|
|
type alloc_result =
|
2012-02-17 06:17:40 -06:00
|
|
|
{bcx: block,
|
2011-09-02 17:34:58 -05:00
|
|
|
val: ValueRef,
|
|
|
|
unit_ty: ty::t,
|
|
|
|
llunitty: TypeRef};
|
2011-08-22 13:48:00 -05:00
|
|
|
|
2012-02-17 06:17:40 -06:00
|
|
|
fn alloc(bcx: block, vec_ty: ty::t, elts: uint) -> alloc_result {
|
2012-03-22 15:44:20 -05:00
|
|
|
let _icx = bcx.insn_ctxt("tvec::alloc");
|
2012-02-21 07:20:18 -06:00
|
|
|
let ccx = bcx.ccx();
|
|
|
|
let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
|
2012-03-12 04:05:15 -05:00
|
|
|
let llunitty = type_of::type_of(ccx, unit_ty);
|
2011-10-14 22:38:24 -05:00
|
|
|
let llvecty = T_vec(ccx, llunitty);
|
2012-03-12 04:05:15 -05:00
|
|
|
let unit_sz = llsize_of(ccx, llunitty);
|
2011-08-25 03:18:02 -05:00
|
|
|
|
2011-10-14 22:38:24 -05:00
|
|
|
let fill = Mul(bcx, C_uint(ccx, elts), unit_sz);
|
2012-03-12 04:05:15 -05:00
|
|
|
let alloc = if elts < 4u { Mul(bcx, C_int(ccx, 4), unit_sz) }
|
|
|
|
else { fill };
|
2011-09-02 17:34:58 -05:00
|
|
|
let {bcx: bcx, val: vptr} = alloc_raw(bcx, fill, alloc);
|
2011-08-29 15:30:18 -05:00
|
|
|
let vptr = PointerCast(bcx, vptr, T_ptr(llvecty));
|
2011-09-07 14:10:37 -05:00
|
|
|
|
2011-09-02 17:34:58 -05:00
|
|
|
ret {bcx: bcx,
|
2011-09-27 13:21:44 -05:00
|
|
|
val: vptr,
|
2011-09-02 17:34:58 -05:00
|
|
|
unit_ty: unit_ty,
|
|
|
|
llunitty: llunitty};
|
2011-08-25 03:18:02 -05:00
|
|
|
}
|
2011-08-29 15:30:18 -05:00
|
|
|
|
2012-02-17 06:17:40 -06:00
|
|
|
fn duplicate(bcx: block, vptr: ValueRef, vec_ty: ty::t) -> result {
|
2012-03-22 15:44:20 -05:00
|
|
|
let _icx = bcx.insn_ctxt("tvec::duplicate");
|
2012-02-21 07:20:18 -06:00
|
|
|
let ccx = bcx.ccx();
|
2011-10-10 06:32:50 -05:00
|
|
|
let fill = get_fill(bcx, vptr);
|
2011-10-14 22:38:24 -05:00
|
|
|
let size = Add(bcx, fill, llsize_of(ccx, ccx.opaque_vec_type));
|
2012-03-23 08:45:47 -05:00
|
|
|
let newptr = shared_malloc(bcx, val_ty(vptr), size);
|
|
|
|
call_memmove(bcx, newptr, vptr, size);
|
2012-02-21 07:20:18 -06:00
|
|
|
let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
|
2011-10-26 00:23:28 -05:00
|
|
|
Store(bcx, fill, GEPi(bcx, newptr, [0, abi::vec_elt_alloc]));
|
2012-03-23 08:45:47 -05:00
|
|
|
let bcx = if ty::type_needs_drop(bcx.tcx(), unit_ty) {
|
|
|
|
iter_vec(bcx, newptr, vec_ty, base::take_ty)
|
|
|
|
} else { bcx };
|
2011-10-10 06:32:50 -05:00
|
|
|
ret rslt(bcx, newptr);
|
2011-08-25 03:18:02 -05:00
|
|
|
}
|
2012-02-17 06:17:40 -06:00
|
|
|
fn make_free_glue(bcx: block, vptr: ValueRef, vec_ty: ty::t) ->
|
|
|
|
block {
|
2012-03-22 15:44:20 -05:00
|
|
|
let _icx = bcx.insn_ctxt("tvec::make_free_glue");
|
2012-02-21 07:20:18 -06:00
|
|
|
let tcx = bcx.tcx(), unit_ty = ty::sequence_element_type(tcx, vec_ty);
|
2012-02-17 06:17:40 -06:00
|
|
|
base::with_cond(bcx, IsNotNull(bcx, vptr)) {|bcx|
|
|
|
|
let bcx = if ty::type_needs_drop(tcx, unit_ty) {
|
|
|
|
iter_vec(bcx, vptr, vec_ty, base::drop_ty)
|
|
|
|
} else { bcx };
|
|
|
|
base::trans_shared_free(bcx, vptr)
|
2011-08-22 13:48:00 -05:00
|
|
|
}
|
2011-08-22 15:30:53 -05:00
|
|
|
}
|
|
|
|
|
2012-02-17 06:17:40 -06:00
|
|
|
fn trans_vec(bcx: block, args: [@ast::expr], id: ast::node_id,
|
|
|
|
dest: dest) -> block {
|
2012-03-22 15:44:20 -05:00
|
|
|
let _icx = bcx.insn_ctxt("tvec::trans_vec");
|
2012-03-15 08:47:03 -05:00
|
|
|
let ccx = bcx.ccx();
|
|
|
|
let mut bcx = bcx;
|
2012-01-27 06:17:06 -06:00
|
|
|
if dest == base::ignore {
|
2012-03-27 08:14:12 -05:00
|
|
|
for vec::each(args) {|arg|
|
2012-01-27 06:17:06 -06:00
|
|
|
bcx = base::trans_expr(bcx, arg, base::ignore);
|
2011-09-27 03:50:18 -05:00
|
|
|
}
|
|
|
|
ret bcx;
|
|
|
|
}
|
2012-02-02 05:37:17 -06:00
|
|
|
let vec_ty = node_id_type(bcx, id);
|
2012-03-15 08:47:03 -05:00
|
|
|
let mut {bcx: bcx,
|
|
|
|
val: vptr,
|
|
|
|
unit_ty: unit_ty,
|
|
|
|
llunitty: llunitty} = alloc(bcx, vec_ty, args.len());
|
2011-08-22 15:30:53 -05:00
|
|
|
|
2011-09-27 06:19:55 -05:00
|
|
|
add_clean_free(bcx, vptr, true);
|
2011-08-22 15:30:53 -05:00
|
|
|
// Store the individual elements.
|
2011-10-10 06:32:50 -05:00
|
|
|
let dataptr = get_dataptr(bcx, vptr, llunitty);
|
2012-03-15 08:47:03 -05:00
|
|
|
let mut i = 0u, temp_cleanups = [vptr];
|
2012-03-27 08:14:12 -05:00
|
|
|
for vec::each(args) {|e|
|
2012-03-12 04:05:15 -05:00
|
|
|
let lleltptr = InBoundsGEP(bcx, dataptr, [C_uint(ccx, i)]);
|
2012-01-27 06:17:06 -06:00
|
|
|
bcx = base::trans_expr_save_in(bcx, e, lleltptr);
|
2011-09-27 03:50:18 -05:00
|
|
|
add_clean_temp_mem(bcx, lleltptr, unit_ty);
|
|
|
|
temp_cleanups += [lleltptr];
|
2011-08-22 13:48:00 -05:00
|
|
|
i += 1u;
|
|
|
|
}
|
2012-03-27 08:14:12 -05:00
|
|
|
for vec::each(temp_cleanups) {|cln| revoke_clean(bcx, cln); }
|
2012-01-27 06:17:06 -06:00
|
|
|
ret base::store_in_dest(bcx, vptr, dest);
|
2011-08-22 13:48:00 -05:00
|
|
|
}
|
2011-09-27 13:21:44 -05:00
|
|
|
|
2012-04-09 19:32:49 -05:00
|
|
|
fn trans_vstore(bcx: block, e: @ast::expr,
|
|
|
|
v: ast::vstore, dest: dest) -> block {
|
|
|
|
alt e.node {
|
|
|
|
ast::expr_lit(@{node: ast::lit_str(s), span: _}) {
|
2012-04-16 18:17:51 -05:00
|
|
|
ret trans_estr(bcx, s, v, dest);
|
2012-04-09 19:32:49 -05:00
|
|
|
}
|
|
|
|
ast::expr_vec(es, mutbl) {
|
|
|
|
bcx.ccx().sess.span_unimpl(e.span, "unhandled tvec::trans_vstore");
|
|
|
|
}
|
|
|
|
_ {
|
|
|
|
bcx.sess().span_bug(e.span, "vstore on non-sequence type");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-17 17:07:38 -05:00
|
|
|
fn get_base_and_len(cx: block, v: ValueRef, e_ty: ty::t)
|
|
|
|
-> (ValueRef, ValueRef) {
|
|
|
|
|
|
|
|
let tcx = cx.ccx().tcx;
|
|
|
|
let vec_ty = ty::type_autoderef(tcx, e_ty);
|
|
|
|
let unit_ty = ty::sequence_element_type(tcx, vec_ty);
|
|
|
|
let vstore = alt ty::get(vec_ty).struct {
|
|
|
|
ty::ty_estr(vst) | ty::ty_evec(_, vst) { vst }
|
|
|
|
_ { ty::vstore_uniq }
|
|
|
|
};
|
|
|
|
|
|
|
|
alt vstore {
|
|
|
|
ty::vstore_fixed(n) {
|
|
|
|
let base = GEPi(cx, v, [0, 0]);
|
2012-04-18 19:02:00 -05:00
|
|
|
let len = C_uint(cx.ccx(), n + 1u /* +1 for null */);
|
2012-04-17 17:07:38 -05:00
|
|
|
(base, len)
|
|
|
|
}
|
|
|
|
ty::vstore_slice(_) {
|
|
|
|
let base = Load(cx, GEPi(cx, v, [0, abi::slice_elt_base]));
|
|
|
|
let len = Load(cx, GEPi(cx, v, [0, abi::slice_elt_len]));
|
|
|
|
(base, len)
|
|
|
|
}
|
|
|
|
ty::vstore_uniq {
|
|
|
|
let base = tvec::get_dataptr(cx, v,
|
|
|
|
type_of::type_of(cx.ccx(), unit_ty));
|
|
|
|
let len = tvec::get_fill(cx, v);
|
|
|
|
(base, len)
|
|
|
|
}
|
|
|
|
ty::vstore_box {
|
|
|
|
cx.ccx().sess.unimpl("unhandled tvec::get_base_and_len");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-09 19:32:49 -05:00
|
|
|
fn trans_estr(bcx: block, s: str, vstore: ast::vstore,
|
2012-04-16 18:17:51 -05:00
|
|
|
dest: dest) -> block {
|
2012-04-09 19:32:49 -05:00
|
|
|
let _icx = bcx.insn_ctxt("tvec::trans_estr");
|
2012-04-10 20:34:21 -05:00
|
|
|
let ccx = bcx.ccx();
|
|
|
|
|
|
|
|
let c = alt vstore {
|
2012-04-09 19:32:49 -05:00
|
|
|
ast::vstore_fixed(_)
|
|
|
|
{
|
2012-04-18 19:02:00 -05:00
|
|
|
// "hello"/_ => "hello"/5 => [i8 x 6] in llvm
|
2012-04-10 20:34:21 -05:00
|
|
|
#debug("trans_estr: fixed: %s", s);
|
|
|
|
C_postr(s)
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::vstore_slice(_) {
|
2012-04-18 19:02:00 -05:00
|
|
|
// "hello" => (*i8, 6u) in llvm
|
2012-04-10 20:34:21 -05:00
|
|
|
#debug("trans_estr: slice '%s'", s);
|
|
|
|
let cs = PointerCast(bcx, C_cstr(ccx, s), T_ptr(T_i8()));
|
2012-04-18 19:02:00 -05:00
|
|
|
C_struct([cs, C_uint(ccx, str::len(s) + 1u /* +1 for null */)])
|
2012-04-09 19:32:49 -05:00
|
|
|
}
|
2012-04-10 20:34:21 -05:00
|
|
|
|
2012-04-16 18:17:51 -05:00
|
|
|
ast::vstore_uniq {
|
|
|
|
let cs = PointerCast(bcx, C_cstr(ccx, s), T_ptr(T_i8()));
|
|
|
|
let len = C_uint(ccx, str::len(s));
|
|
|
|
Call(bcx, ccx.upcalls.str_new_uniq, [cs, len])
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::vstore_box {
|
|
|
|
let cs = PointerCast(bcx, C_cstr(ccx, s), T_ptr(T_i8()));
|
|
|
|
let len = C_uint(ccx, str::len(s));
|
|
|
|
Call(bcx, ccx.upcalls.str_new_shared, [cs, len])
|
2012-04-09 19:32:49 -05:00
|
|
|
}
|
2012-04-10 20:34:21 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
#debug("trans_estr: type: %s", val_str(ccx.tn, c));
|
|
|
|
base::store_in_dest(bcx, c, dest)
|
2012-04-09 19:32:49 -05:00
|
|
|
}
|
|
|
|
|
2012-03-12 04:05:15 -05:00
|
|
|
fn trans_append(bcx: block, vec_ty: ty::t, lhsptr: ValueRef,
|
2012-02-17 06:17:40 -06:00
|
|
|
rhs: ValueRef) -> block {
|
2012-03-22 15:44:20 -05:00
|
|
|
let _icx = bcx.insn_ctxt("tvec::trans_append");
|
2011-08-22 13:48:00 -05:00
|
|
|
// Cast to opaque interior vector types if necessary.
|
2012-03-12 04:05:15 -05:00
|
|
|
let ccx = bcx.ccx();
|
|
|
|
let unit_ty = ty::sequence_element_type(ccx.tcx, vec_ty);
|
2012-02-21 07:25:53 -06:00
|
|
|
let strings = alt check ty::get(vec_ty).struct {
|
2012-01-19 00:37:22 -06:00
|
|
|
ty::ty_str { true }
|
2011-10-10 06:32:50 -05:00
|
|
|
ty::ty_vec(_) { false }
|
|
|
|
};
|
2011-08-22 19:35:38 -05:00
|
|
|
|
2012-03-12 04:05:15 -05:00
|
|
|
let llunitty = type_of::type_of(ccx, unit_ty);
|
2011-08-22 13:48:00 -05:00
|
|
|
|
2011-08-25 03:18:02 -05:00
|
|
|
let lhs = Load(bcx, lhsptr);
|
2012-02-01 04:04:56 -06:00
|
|
|
let self_append = ICmp(bcx, lib::llvm::IntEQ, lhs, rhs);
|
2011-10-10 06:32:50 -05:00
|
|
|
let lfill = get_fill(bcx, lhs);
|
|
|
|
let rfill = get_fill(bcx, rhs);
|
2012-03-15 08:47:03 -05:00
|
|
|
let mut new_fill = Add(bcx, lfill, rfill);
|
2011-10-14 22:38:24 -05:00
|
|
|
if strings { new_fill = Sub(bcx, new_fill, C_int(ccx, 1)); }
|
|
|
|
let opaque_lhs = PointerCast(bcx, lhsptr,
|
|
|
|
T_ptr(T_ptr(ccx.opaque_vec_type)));
|
2012-03-12 04:05:15 -05:00
|
|
|
Call(bcx, ccx.upcalls.vec_grow,
|
2011-10-20 04:42:40 -05:00
|
|
|
[opaque_lhs, new_fill]);
|
2011-08-25 03:18:02 -05:00
|
|
|
// Was overwritten if we resized
|
2011-10-10 06:32:50 -05:00
|
|
|
let lhs = Load(bcx, lhsptr);
|
2012-03-12 04:05:15 -05:00
|
|
|
let rhs = Select(bcx, self_append, lhs, rhs);
|
2011-08-25 03:18:02 -05:00
|
|
|
|
2011-10-10 06:32:50 -05:00
|
|
|
let lhs_data = get_dataptr(bcx, lhs, llunitty);
|
2012-03-15 08:47:03 -05:00
|
|
|
let mut lhs_off = lfill;
|
2011-10-14 22:38:24 -05:00
|
|
|
if strings { lhs_off = Sub(bcx, lhs_off, C_int(ccx, 1)); }
|
2011-08-25 03:18:02 -05:00
|
|
|
let write_ptr = pointer_add(bcx, lhs_data, lhs_off);
|
2011-09-02 17:12:27 -05:00
|
|
|
let write_ptr_ptr = do_spill_noroot(bcx, write_ptr);
|
2012-03-12 04:05:15 -05:00
|
|
|
iter_vec_raw(bcx, rhs, vec_ty, rfill, {|bcx, addr, _ty|
|
|
|
|
let write_ptr = Load(bcx, write_ptr_ptr);
|
|
|
|
let bcx = copy_val(bcx, INIT, write_ptr,
|
|
|
|
load_if_immediate(bcx, addr, unit_ty), unit_ty);
|
|
|
|
Store(bcx, InBoundsGEP(bcx, write_ptr, [C_int(ccx, 1)]),
|
|
|
|
write_ptr_ptr);
|
2012-03-26 05:39:20 -05:00
|
|
|
bcx
|
2012-03-12 04:05:15 -05:00
|
|
|
})
|
2011-08-22 13:48:00 -05:00
|
|
|
}
|
|
|
|
|
2012-02-17 06:17:40 -06:00
|
|
|
fn trans_append_literal(bcx: block, vptrptr: ValueRef, vec_ty: ty::t,
|
|
|
|
vals: [@ast::expr]) -> block {
|
2012-03-22 15:44:20 -05:00
|
|
|
let _icx = bcx.insn_ctxt("tvec::trans_append_literal");
|
2012-03-21 09:42:20 -05:00
|
|
|
let mut bcx = bcx, ccx = bcx.ccx();
|
2012-02-21 07:20:18 -06:00
|
|
|
let elt_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
|
2012-03-22 10:02:34 -05:00
|
|
|
let elt_llty = type_of::type_of(ccx, elt_ty);
|
|
|
|
let elt_sz = shape::llsize_of(ccx, elt_llty);
|
|
|
|
let scratch = base::alloca(bcx, elt_llty);
|
2012-03-27 08:14:12 -05:00
|
|
|
for vec::each(vals) {|val|
|
2012-03-22 10:02:34 -05:00
|
|
|
bcx = base::trans_expr_save_in(bcx, val, scratch);
|
|
|
|
let vptr = Load(bcx, vptrptr);
|
|
|
|
let old_fill = get_fill(bcx, vptr);
|
|
|
|
let new_fill = Add(bcx, old_fill, elt_sz);
|
|
|
|
let do_grow = ICmp(bcx, lib::llvm::IntUGT, new_fill,
|
|
|
|
get_alloc(bcx, vptr));
|
|
|
|
bcx = base::with_cond(bcx, do_grow) {|bcx|
|
|
|
|
let pt = PointerCast(bcx, vptrptr,
|
|
|
|
T_ptr(T_ptr(ccx.opaque_vec_type)));
|
|
|
|
Call(bcx, ccx.upcalls.vec_grow, [pt, new_fill]);
|
|
|
|
bcx
|
|
|
|
};
|
|
|
|
let vptr = Load(bcx, vptrptr);
|
|
|
|
set_fill(bcx, vptr, new_fill);
|
|
|
|
let targetptr = pointer_add(bcx, get_dataptr(bcx, vptr, elt_llty),
|
|
|
|
old_fill);
|
2012-03-23 08:45:47 -05:00
|
|
|
call_memmove(bcx, targetptr, scratch, elt_sz);
|
2011-08-24 06:53:34 -05:00
|
|
|
}
|
2012-03-22 10:02:34 -05:00
|
|
|
bcx
|
2011-08-24 06:53:34 -05:00
|
|
|
}
|
|
|
|
|
2012-02-17 06:17:40 -06:00
|
|
|
fn trans_add(bcx: block, vec_ty: ty::t, lhs: ValueRef,
|
|
|
|
rhs: ValueRef, dest: dest) -> block {
|
2012-03-22 15:44:20 -05:00
|
|
|
let _icx = bcx.insn_ctxt("tvec::trans_add");
|
2012-02-21 07:20:18 -06:00
|
|
|
let ccx = bcx.ccx();
|
2012-03-19 16:06:59 -05:00
|
|
|
|
|
|
|
if ty::get(vec_ty).struct == ty::ty_str {
|
|
|
|
let n = Call(bcx, ccx.upcalls.str_concat, [lhs, rhs]);
|
|
|
|
ret base::store_in_dest(bcx, n, dest);
|
|
|
|
}
|
|
|
|
|
2012-02-21 07:20:18 -06:00
|
|
|
let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
|
2012-03-12 04:05:15 -05:00
|
|
|
let llunitty = type_of::type_of(ccx, unit_ty);
|
2011-08-29 15:30:18 -05:00
|
|
|
|
2011-10-10 06:32:50 -05:00
|
|
|
let lhs_fill = get_fill(bcx, lhs);
|
|
|
|
let rhs_fill = get_fill(bcx, rhs);
|
2011-08-25 03:18:02 -05:00
|
|
|
let new_fill = Add(bcx, lhs_fill, rhs_fill);
|
2012-03-15 08:47:03 -05:00
|
|
|
let mut {bcx: bcx, val: new_vec_ptr} = alloc_raw(bcx, new_fill, new_fill);
|
2011-10-14 22:38:24 -05:00
|
|
|
new_vec_ptr = PointerCast(bcx, new_vec_ptr, T_ptr(T_vec(ccx, llunitty)));
|
2011-08-25 03:18:02 -05:00
|
|
|
|
2011-09-27 13:21:44 -05:00
|
|
|
let write_ptr_ptr = do_spill_noroot
|
2011-10-10 06:32:50 -05:00
|
|
|
(bcx, get_dataptr(bcx, new_vec_ptr, llunitty));
|
2012-02-17 06:17:40 -06:00
|
|
|
let copy_fn = fn@(bcx: block, addr: ValueRef,
|
|
|
|
_ty: ty::t) -> block {
|
2012-02-21 07:20:18 -06:00
|
|
|
let ccx = bcx.ccx();
|
2012-01-11 11:58:05 -06:00
|
|
|
let write_ptr = Load(bcx, write_ptr_ptr);
|
|
|
|
let bcx = copy_val(bcx, INIT, write_ptr,
|
|
|
|
load_if_immediate(bcx, addr, unit_ty), unit_ty);
|
2012-03-12 04:05:15 -05:00
|
|
|
Store(bcx, InBoundsGEP(bcx, write_ptr, [C_int(ccx, 1)]),
|
2012-01-11 11:58:05 -06:00
|
|
|
write_ptr_ptr);
|
|
|
|
ret bcx;
|
|
|
|
};
|
2011-08-22 18:39:18 -05:00
|
|
|
|
2011-10-10 06:32:50 -05:00
|
|
|
let bcx = iter_vec_raw(bcx, lhs, vec_ty, lhs_fill, copy_fn);
|
2012-03-15 08:47:03 -05:00
|
|
|
let bcx = iter_vec_raw(bcx, rhs, vec_ty, rhs_fill, copy_fn);
|
2012-01-27 06:17:06 -06:00
|
|
|
ret base::store_in_dest(bcx, new_vec_ptr, dest);
|
2011-08-29 09:14:24 -05:00
|
|
|
}
|
2011-08-22 13:48:00 -05:00
|
|
|
|
2012-02-17 06:17:40 -06:00
|
|
|
type val_and_ty_fn = fn@(block, ValueRef, ty::t) -> result;
|
2011-08-22 13:48:00 -05:00
|
|
|
|
2012-02-17 06:17:40 -06:00
|
|
|
type iter_vec_block = fn(block, ValueRef, ty::t) -> block;
|
2011-08-22 13:48:00 -05:00
|
|
|
|
2012-02-17 06:17:40 -06:00
|
|
|
fn iter_vec_raw(bcx: block, vptr: ValueRef, vec_ty: ty::t,
|
|
|
|
fill: ValueRef, f: iter_vec_block) -> block {
|
2012-03-22 15:44:20 -05:00
|
|
|
let _icx = bcx.insn_ctxt("tvec::iter_vec_raw");
|
2012-02-21 07:20:18 -06:00
|
|
|
let ccx = bcx.ccx();
|
|
|
|
let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
|
2012-03-12 04:05:15 -05:00
|
|
|
let llunitty = type_of::type_of(ccx, unit_ty);
|
2011-11-03 04:57:54 -05:00
|
|
|
let vptr = PointerCast(bcx, vptr, T_ptr(T_vec(ccx, llunitty)));
|
2011-10-10 06:32:50 -05:00
|
|
|
let data_ptr = get_dataptr(bcx, vptr, llunitty);
|
2011-08-25 03:18:02 -05:00
|
|
|
|
|
|
|
// Calculate the last pointer address we want to handle.
|
2012-02-21 07:20:18 -06:00
|
|
|
// FIXME: Optimize this when the size of the unit type is statically
|
2011-08-25 03:18:02 -05:00
|
|
|
// known to not use pointer casts, which tend to confuse LLVM.
|
|
|
|
let data_end_ptr = pointer_add(bcx, data_ptr, fill);
|
|
|
|
|
|
|
|
// Now perform the iteration.
|
2012-02-17 06:17:40 -06:00
|
|
|
let header_cx = sub_block(bcx, "iter_vec_loop_header");
|
2011-08-25 03:18:02 -05:00
|
|
|
Br(bcx, header_cx.llbb);
|
2011-09-09 07:20:15 -05:00
|
|
|
let data_ptr = Phi(header_cx, val_ty(data_ptr), [data_ptr], [bcx.llbb]);
|
2011-09-02 17:34:58 -05:00
|
|
|
let not_yet_at_end =
|
2012-02-01 04:04:56 -06:00
|
|
|
ICmp(header_cx, lib::llvm::IntULT, data_ptr, data_end_ptr);
|
2012-02-17 06:17:40 -06:00
|
|
|
let body_cx = sub_block(header_cx, "iter_vec_loop_body");
|
|
|
|
let next_cx = sub_block(header_cx, "iter_vec_next");
|
2011-08-25 03:18:02 -05:00
|
|
|
CondBr(header_cx, not_yet_at_end, body_cx.llbb, next_cx.llbb);
|
2012-03-15 08:47:03 -05:00
|
|
|
let body_cx = f(body_cx, data_ptr, unit_ty);
|
2012-03-12 04:05:15 -05:00
|
|
|
AddIncomingToPhi(data_ptr, InBoundsGEP(body_cx, data_ptr,
|
|
|
|
[C_int(ccx, 1)]), body_cx.llbb);
|
2011-08-25 03:18:02 -05:00
|
|
|
Br(body_cx, header_cx.llbb);
|
2011-08-30 06:50:58 -05:00
|
|
|
ret next_cx;
|
2011-08-22 13:48:00 -05:00
|
|
|
}
|
2011-08-25 03:18:02 -05:00
|
|
|
|
2012-02-17 06:17:40 -06:00
|
|
|
fn iter_vec(bcx: block, vptr: ValueRef, vec_ty: ty::t,
|
|
|
|
f: iter_vec_block) -> block {
|
2012-03-22 15:44:20 -05:00
|
|
|
let _icx = bcx.insn_ctxt("tvec::iter_vec");
|
2012-02-21 07:20:18 -06:00
|
|
|
let vptr = PointerCast(bcx, vptr, T_ptr(bcx.ccx().opaque_vec_type));
|
2011-10-10 06:32:50 -05:00
|
|
|
ret iter_vec_raw(bcx, vptr, vec_ty, get_fill(bcx, vptr), f);
|
2011-08-29 09:14:24 -05:00
|
|
|
}
|
|
|
|
|
2011-08-24 06:53:34 -05:00
|
|
|
//
|
|
|
|
// Local Variables:
|
|
|
|
// mode: rust
|
|
|
|
// fill-column: 78;
|
|
|
|
// indent-tabs-mode: nil
|
|
|
|
// c-basic-offset: 4
|
|
|
|
// buffer-file-coding-system: utf-8-unix
|
|
|
|
// End:
|
|
|
|
//
|