2011-08-22 15:30:53 -05:00
|
|
|
import std::vec;
|
2011-08-22 13:48:00 -05:00
|
|
|
import std::option::none;
|
|
|
|
import syntax::ast;
|
|
|
|
import lib::llvm::llvm::{ValueRef, TypeRef};
|
|
|
|
import back::abi;
|
|
|
|
import trans::{call_memmove, trans_shared_malloc, llsize_of,
|
|
|
|
type_of_or_i8, incr_ptr, INIT, copy_val, load_if_immediate,
|
|
|
|
alloca, array_alloca, size_of, llderivedtydescs_block_ctxt,
|
|
|
|
lazily_emit_tydesc_glue, get_tydesc, load_inbounds,
|
|
|
|
move_val_if_temp, trans_lval, node_id_type,
|
2011-08-24 20:36:51 -05:00
|
|
|
new_sub_block_ctxt, tps_normal};
|
2011-08-24 07:54:55 -05:00
|
|
|
import bld = trans_build;
|
2011-08-22 13:48:00 -05:00
|
|
|
import trans_common::*;
|
|
|
|
|
2011-08-22 15:30:53 -05:00
|
|
|
fn alloc_with_heap(bcx: @block_ctxt, typ: &ty::t, vecsz: uint) ->
|
|
|
|
{bcx: @block_ctxt,
|
|
|
|
unit_ty: ty::t,
|
|
|
|
llunitsz: ValueRef,
|
|
|
|
llptr: ValueRef,
|
|
|
|
llfirsteltptr: ValueRef} {
|
|
|
|
|
2011-08-22 13:48:00 -05:00
|
|
|
let unit_ty;
|
|
|
|
alt ty::struct(bcx_tcx(bcx), typ) {
|
|
|
|
ty::ty_vec(mt) { unit_ty = mt.ty; }
|
2011-08-27 18:36:48 -05:00
|
|
|
_ { bcx_ccx(bcx).sess.bug(~"non-ivec type in trans_ivec"); }
|
2011-08-22 13:48:00 -05:00
|
|
|
}
|
|
|
|
let llunitty = type_of_or_i8(bcx, unit_ty);
|
|
|
|
|
|
|
|
let ares = alloc(bcx, unit_ty);
|
|
|
|
bcx = ares.bcx;
|
|
|
|
let llvecptr = ares.llptr;
|
|
|
|
let unit_sz = ares.llunitsz;
|
|
|
|
let llalen = ares.llalen;
|
|
|
|
|
|
|
|
add_clean_temp(bcx, llvecptr, typ);
|
|
|
|
|
2011-08-24 07:54:55 -05:00
|
|
|
let lllen = bld::Mul(bcx, C_uint(vecsz), unit_sz);
|
2011-08-22 13:48:00 -05:00
|
|
|
// Allocate the vector pieces and store length and allocated length.
|
|
|
|
|
|
|
|
let llfirsteltptr;
|
2011-08-22 15:30:53 -05:00
|
|
|
if vecsz > 0u && vecsz <= abi::ivec_default_length {
|
2011-08-22 13:48:00 -05:00
|
|
|
// Interior case.
|
|
|
|
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Store(bcx, lllen,
|
|
|
|
bld::InBoundsGEP(bcx, llvecptr,
|
2011-08-22 13:48:00 -05:00
|
|
|
[C_int(0),
|
|
|
|
C_uint(abi::ivec_elt_len)]));
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Store(bcx, llalen,
|
|
|
|
bld::InBoundsGEP(bcx, llvecptr,
|
2011-08-22 13:48:00 -05:00
|
|
|
[C_int(0),
|
|
|
|
C_uint(abi::ivec_elt_alen)]));
|
|
|
|
llfirsteltptr =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::InBoundsGEP(bcx, llvecptr,
|
2011-08-22 13:48:00 -05:00
|
|
|
[C_int(0), C_uint(abi::ivec_elt_elems),
|
|
|
|
C_int(0)]);
|
|
|
|
} else {
|
|
|
|
// Heap case.
|
|
|
|
|
|
|
|
let stub_z = [C_int(0), C_uint(abi::ivec_heap_stub_elt_zero)];
|
|
|
|
let stub_a = [C_int(0), C_uint(abi::ivec_heap_stub_elt_alen)];
|
|
|
|
let stub_p = [C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)];
|
|
|
|
let llstubty = T_ivec_heap(llunitty);
|
2011-08-24 07:54:55 -05:00
|
|
|
let llstubptr = bld::PointerCast(bcx, llvecptr, T_ptr(llstubty));
|
|
|
|
bld::Store(bcx, C_int(0), bld::InBoundsGEP(bcx, llstubptr, stub_z));
|
2011-08-22 13:48:00 -05:00
|
|
|
let llheapty = T_ivec_heap_part(llunitty);
|
2011-08-22 15:30:53 -05:00
|
|
|
if vecsz == 0u {
|
2011-08-22 13:48:00 -05:00
|
|
|
// Null heap pointer indicates a zero-length vector.
|
|
|
|
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Store(bcx, llalen, bld::InBoundsGEP(bcx, llstubptr, stub_a));
|
|
|
|
bld::Store(bcx, C_null(T_ptr(llheapty)),
|
|
|
|
bld::InBoundsGEP(bcx, llstubptr, stub_p));
|
2011-08-22 13:48:00 -05:00
|
|
|
llfirsteltptr = C_null(T_ptr(llunitty));
|
|
|
|
} else {
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Store(bcx, lllen, bld::InBoundsGEP(bcx, llstubptr, stub_a));
|
2011-08-22 13:48:00 -05:00
|
|
|
|
2011-08-24 07:54:55 -05:00
|
|
|
let llheapsz = bld::Add(bcx, llsize_of(llheapty), lllen);
|
2011-08-22 13:48:00 -05:00
|
|
|
let rslt = trans_shared_malloc(bcx, T_ptr(llheapty), llheapsz);
|
|
|
|
bcx = rslt.bcx;
|
|
|
|
let llheapptr = rslt.val;
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Store(bcx, llheapptr,
|
|
|
|
bld::InBoundsGEP(bcx, llstubptr, stub_p));
|
2011-08-22 13:48:00 -05:00
|
|
|
let heap_l = [C_int(0), C_uint(abi::ivec_heap_elt_len)];
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Store(bcx, lllen, bld::InBoundsGEP(bcx, llheapptr, heap_l));
|
2011-08-22 13:48:00 -05:00
|
|
|
llfirsteltptr =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::InBoundsGEP(bcx, llheapptr,
|
2011-08-22 13:48:00 -05:00
|
|
|
[C_int(0),
|
|
|
|
C_uint(abi::ivec_heap_elt_elems),
|
|
|
|
C_int(0)]);
|
|
|
|
}
|
|
|
|
}
|
2011-08-22 15:30:53 -05:00
|
|
|
ret {
|
|
|
|
bcx: bcx,
|
|
|
|
unit_ty: unit_ty,
|
|
|
|
llunitsz: unit_sz,
|
|
|
|
llptr: llvecptr,
|
|
|
|
llfirsteltptr: llfirsteltptr};
|
|
|
|
}
|
|
|
|
|
|
|
|
fn trans_ivec(bcx: @block_ctxt, args: &[@ast::expr],
|
|
|
|
id: ast::node_id) -> result {
|
2011-08-22 13:48:00 -05:00
|
|
|
|
2011-08-22 15:30:53 -05:00
|
|
|
let typ = node_id_type(bcx_ccx(bcx), id);
|
|
|
|
let alloc_res = alloc_with_heap(bcx, typ, vec::len(args));
|
|
|
|
|
|
|
|
let bcx = alloc_res.bcx;
|
|
|
|
let unit_ty = alloc_res.unit_ty;
|
|
|
|
let llunitsz = alloc_res.llunitsz;
|
|
|
|
let llvecptr = alloc_res.llptr;
|
|
|
|
let llfirsteltptr = alloc_res.llfirsteltptr;
|
|
|
|
|
|
|
|
// Store the individual elements.
|
2011-08-22 13:48:00 -05:00
|
|
|
let i = 0u;
|
|
|
|
for e: @ast::expr in args {
|
|
|
|
let lv = trans_lval(bcx, e);
|
|
|
|
bcx = lv.res.bcx;
|
|
|
|
let lleltptr;
|
|
|
|
if ty::type_has_dynamic_size(bcx_tcx(bcx), unit_ty) {
|
|
|
|
lleltptr =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::InBoundsGEP(bcx, llfirsteltptr,
|
|
|
|
[bld::Mul(bcx, C_uint(i), llunitsz)]);
|
2011-08-22 13:48:00 -05:00
|
|
|
} else {
|
2011-08-24 07:54:55 -05:00
|
|
|
lleltptr = bld::InBoundsGEP(bcx, llfirsteltptr, [C_uint(i)]);
|
2011-08-22 13:48:00 -05:00
|
|
|
}
|
|
|
|
bcx = move_val_if_temp(bcx, INIT, lleltptr, lv, unit_ty);
|
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
ret rslt(bcx, llvecptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the length of an interior vector and a pointer to its first
|
|
|
|
// element, in that order.
|
|
|
|
fn get_len_and_data(bcx: &@block_ctxt, orig_v: ValueRef, unit_ty: ty::t)
|
|
|
|
-> {len: ValueRef, data: ValueRef, bcx: @block_ctxt} {
|
|
|
|
// If this interior vector has dynamic size, we can't assume anything
|
|
|
|
// about the LLVM type of the value passed in, so we cast it to an
|
|
|
|
// opaque vector type.
|
|
|
|
let v;
|
|
|
|
if ty::type_has_dynamic_size(bcx_tcx(bcx), unit_ty) {
|
2011-08-24 07:54:55 -05:00
|
|
|
v = bld::PointerCast(bcx, orig_v, T_ptr(T_opaque_ivec()));
|
2011-08-22 13:48:00 -05:00
|
|
|
} else { v = orig_v; }
|
|
|
|
|
|
|
|
let llunitty = type_of_or_i8(bcx, unit_ty);
|
|
|
|
let stack_len =
|
|
|
|
load_inbounds(bcx, v, [C_int(0), C_uint(abi::ivec_elt_len)]);
|
|
|
|
let stack_elem =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::InBoundsGEP(bcx, v,
|
2011-08-22 13:48:00 -05:00
|
|
|
[C_int(0), C_uint(abi::ivec_elt_elems),
|
|
|
|
C_int(0)]);
|
|
|
|
let on_heap =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::ICmp(bcx, lib::llvm::LLVMIntEQ, stack_len, C_int(0));
|
2011-08-26 23:34:56 -05:00
|
|
|
let on_heap_cx = new_sub_block_ctxt(bcx, ~"on_heap");
|
|
|
|
let next_cx = new_sub_block_ctxt(bcx, ~"next");
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::CondBr(bcx, on_heap, on_heap_cx.llbb, next_cx.llbb);
|
2011-08-22 13:48:00 -05:00
|
|
|
let heap_stub =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::PointerCast(on_heap_cx, v, T_ptr(T_ivec_heap(llunitty)));
|
2011-08-22 13:48:00 -05:00
|
|
|
let heap_ptr =
|
|
|
|
load_inbounds(on_heap_cx, heap_stub,
|
|
|
|
[C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)]);
|
|
|
|
|
|
|
|
// Check whether the heap pointer is null. If it is, the vector length
|
|
|
|
// is truly zero.
|
|
|
|
|
|
|
|
let llstubty = T_ivec_heap(llunitty);
|
|
|
|
let llheapptrty = struct_elt(llstubty, abi::ivec_heap_stub_elt_ptr);
|
|
|
|
let heap_ptr_is_null =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::ICmp(on_heap_cx, lib::llvm::LLVMIntEQ, heap_ptr,
|
2011-08-22 13:48:00 -05:00
|
|
|
C_null(T_ptr(llheapptrty)));
|
2011-08-26 23:34:56 -05:00
|
|
|
let zero_len_cx = new_sub_block_ctxt(bcx, ~"zero_len");
|
|
|
|
let nonzero_len_cx = new_sub_block_ctxt(bcx, ~"nonzero_len");
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::CondBr(on_heap_cx, heap_ptr_is_null, zero_len_cx.llbb,
|
2011-08-22 13:48:00 -05:00
|
|
|
nonzero_len_cx.llbb);
|
|
|
|
// Technically this context is unnecessary, but it makes this function
|
|
|
|
// clearer.
|
|
|
|
|
|
|
|
let zero_len = C_int(0);
|
|
|
|
let zero_elem = C_null(T_ptr(llunitty));
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Br(zero_len_cx, next_cx.llbb);
|
2011-08-22 13:48:00 -05:00
|
|
|
// If we're here, then we actually have a heapified vector.
|
|
|
|
|
|
|
|
let heap_len =
|
|
|
|
load_inbounds(nonzero_len_cx, heap_ptr,
|
|
|
|
[C_int(0), C_uint(abi::ivec_heap_elt_len)]);
|
|
|
|
let heap_elem =
|
|
|
|
{
|
|
|
|
let v =
|
|
|
|
[C_int(0), C_uint(abi::ivec_heap_elt_elems), C_int(0)];
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::InBoundsGEP(nonzero_len_cx, heap_ptr, v)
|
2011-08-22 13:48:00 -05:00
|
|
|
};
|
|
|
|
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Br(nonzero_len_cx, next_cx.llbb);
|
2011-08-22 13:48:00 -05:00
|
|
|
// Now we can figure out the length of `v` and get a pointer to its
|
|
|
|
// first element.
|
|
|
|
|
|
|
|
let len =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Phi(next_cx, T_int(), [stack_len, zero_len, heap_len],
|
2011-08-22 13:48:00 -05:00
|
|
|
[bcx.llbb, zero_len_cx.llbb,
|
|
|
|
nonzero_len_cx.llbb]);
|
|
|
|
let elem =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Phi(next_cx, T_ptr(llunitty),
|
2011-08-22 13:48:00 -05:00
|
|
|
[stack_elem, zero_elem, heap_elem],
|
|
|
|
[bcx.llbb, zero_len_cx.llbb,
|
|
|
|
nonzero_len_cx.llbb]);
|
|
|
|
ret {len: len, data: elem, bcx: next_cx};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a tuple consisting of a pointer to the newly-reserved space and
|
|
|
|
// a block context. Updates the length appropriately.
|
|
|
|
fn reserve_space(cx: &@block_ctxt, llunitty: TypeRef, v: ValueRef,
|
|
|
|
len_needed: ValueRef) -> result {
|
|
|
|
let stack_len_ptr =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::InBoundsGEP(cx, v, [C_int(0), C_uint(abi::ivec_elt_len)]);
|
|
|
|
let stack_len = bld::Load(cx, stack_len_ptr);
|
2011-08-22 13:48:00 -05:00
|
|
|
let alen =
|
|
|
|
load_inbounds(cx, v, [C_int(0), C_uint(abi::ivec_elt_alen)]);
|
|
|
|
// There are four cases we have to consider:
|
|
|
|
// (1) On heap, no resize necessary.
|
|
|
|
// (2) On heap, need to resize.
|
|
|
|
// (3) On stack, no resize necessary.
|
|
|
|
// (4) On stack, need to spill to heap.
|
|
|
|
|
|
|
|
let maybe_on_heap =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::ICmp(cx, lib::llvm::LLVMIntEQ, stack_len, C_int(0));
|
2011-08-26 23:34:56 -05:00
|
|
|
let maybe_on_heap_cx = new_sub_block_ctxt(cx, ~"maybe_on_heap");
|
|
|
|
let on_stack_cx = new_sub_block_ctxt(cx, ~"on_stack");
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::CondBr(cx, maybe_on_heap, maybe_on_heap_cx.llbb,
|
2011-08-22 13:48:00 -05:00
|
|
|
on_stack_cx.llbb);
|
2011-08-26 23:34:56 -05:00
|
|
|
let next_cx = new_sub_block_ctxt(cx, ~"next");
|
2011-08-22 13:48:00 -05:00
|
|
|
// We're possibly on the heap, unless the vector is zero-length.
|
|
|
|
|
|
|
|
let stub_p = [C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)];
|
|
|
|
let stub_ptr =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::PointerCast(maybe_on_heap_cx, v,
|
2011-08-22 13:48:00 -05:00
|
|
|
T_ptr(T_ivec_heap(llunitty)));
|
|
|
|
let heap_ptr = load_inbounds(maybe_on_heap_cx, stub_ptr, stub_p);
|
|
|
|
let on_heap =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::ICmp(maybe_on_heap_cx, lib::llvm::LLVMIntNE, heap_ptr,
|
2011-08-22 13:48:00 -05:00
|
|
|
C_null(val_ty(heap_ptr)));
|
2011-08-26 23:34:56 -05:00
|
|
|
let on_heap_cx = new_sub_block_ctxt(cx, ~"on_heap");
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::CondBr(maybe_on_heap_cx, on_heap, on_heap_cx.llbb,
|
2011-08-22 13:48:00 -05:00
|
|
|
on_stack_cx.llbb);
|
|
|
|
// We're definitely on the heap. Check whether we need to resize.
|
|
|
|
|
|
|
|
let heap_len_ptr =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::InBoundsGEP(on_heap_cx, heap_ptr,
|
2011-08-22 13:48:00 -05:00
|
|
|
[C_int(0),
|
|
|
|
C_uint(abi::ivec_heap_elt_len)]);
|
2011-08-24 07:54:55 -05:00
|
|
|
let heap_len = bld::Load(on_heap_cx, heap_len_ptr);
|
|
|
|
let new_heap_len = bld::Add(on_heap_cx, heap_len, len_needed);
|
2011-08-22 13:48:00 -05:00
|
|
|
let heap_len_unscaled =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::UDiv(on_heap_cx, heap_len, llsize_of(llunitty));
|
2011-08-22 13:48:00 -05:00
|
|
|
let heap_no_resize_needed =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::ICmp(on_heap_cx, lib::llvm::LLVMIntULE, new_heap_len, alen);
|
2011-08-26 23:34:56 -05:00
|
|
|
let heap_no_resize_cx = new_sub_block_ctxt(cx, ~"heap_no_resize");
|
|
|
|
let heap_resize_cx = new_sub_block_ctxt(cx, ~"heap_resize");
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::CondBr(on_heap_cx, heap_no_resize_needed, heap_no_resize_cx.llbb,
|
2011-08-22 13:48:00 -05:00
|
|
|
heap_resize_cx.llbb);
|
|
|
|
// Case (1): We're on the heap and don't need to resize.
|
|
|
|
|
|
|
|
let heap_data_no_resize =
|
|
|
|
{
|
|
|
|
let v =
|
|
|
|
[C_int(0), C_uint(abi::ivec_heap_elt_elems),
|
|
|
|
heap_len_unscaled];
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::InBoundsGEP(heap_no_resize_cx, heap_ptr, v)
|
2011-08-22 13:48:00 -05:00
|
|
|
};
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Store(heap_no_resize_cx, new_heap_len, heap_len_ptr);
|
|
|
|
bld::Br(heap_no_resize_cx, next_cx.llbb);
|
2011-08-22 13:48:00 -05:00
|
|
|
// Case (2): We're on the heap and need to resize. This path is rare,
|
|
|
|
// so we delegate to cold glue.
|
|
|
|
|
|
|
|
{
|
|
|
|
let p =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::PointerCast(heap_resize_cx, v, T_ptr(T_opaque_ivec()));
|
2011-08-22 13:48:00 -05:00
|
|
|
let upcall = bcx_ccx(cx).upcalls.ivec_resize_shared;
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Call(heap_resize_cx, upcall,
|
2011-08-22 13:48:00 -05:00
|
|
|
[cx.fcx.lltaskptr, p, new_heap_len]);
|
|
|
|
}
|
|
|
|
let heap_ptr_resize = load_inbounds(heap_resize_cx, stub_ptr, stub_p);
|
|
|
|
|
|
|
|
let heap_data_resize =
|
|
|
|
{
|
|
|
|
let v =
|
|
|
|
[C_int(0), C_uint(abi::ivec_heap_elt_elems),
|
|
|
|
heap_len_unscaled];
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::InBoundsGEP(heap_resize_cx, heap_ptr_resize, v)
|
2011-08-22 13:48:00 -05:00
|
|
|
};
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Br(heap_resize_cx, next_cx.llbb);
|
2011-08-22 13:48:00 -05:00
|
|
|
// We're on the stack. Check whether we need to spill to the heap.
|
|
|
|
|
2011-08-24 07:54:55 -05:00
|
|
|
let new_stack_len = bld::Add(on_stack_cx, stack_len, len_needed);
|
2011-08-22 13:48:00 -05:00
|
|
|
let stack_no_spill_needed =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::ICmp(on_stack_cx, lib::llvm::LLVMIntULE, new_stack_len,
|
2011-08-22 13:48:00 -05:00
|
|
|
alen);
|
|
|
|
let stack_len_unscaled =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::UDiv(on_stack_cx, stack_len, llsize_of(llunitty));
|
2011-08-26 23:34:56 -05:00
|
|
|
let stack_no_spill_cx = new_sub_block_ctxt(cx, ~"stack_no_spill");
|
|
|
|
let stack_spill_cx = new_sub_block_ctxt(cx, ~"stack_spill");
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::CondBr(on_stack_cx, stack_no_spill_needed,
|
2011-08-22 13:48:00 -05:00
|
|
|
stack_no_spill_cx.llbb, stack_spill_cx.llbb);
|
|
|
|
// Case (3): We're on the stack and don't need to spill.
|
|
|
|
|
|
|
|
let stack_data_no_spill =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::InBoundsGEP(stack_no_spill_cx, v,
|
2011-08-22 13:48:00 -05:00
|
|
|
[C_int(0),
|
|
|
|
C_uint(abi::ivec_elt_elems),
|
|
|
|
stack_len_unscaled]);
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Store(stack_no_spill_cx, new_stack_len, stack_len_ptr);
|
|
|
|
bld::Br(stack_no_spill_cx, next_cx.llbb);
|
2011-08-22 13:48:00 -05:00
|
|
|
// Case (4): We're on the stack and need to spill. Like case (2), this
|
|
|
|
// path is rare, so we delegate to cold glue.
|
|
|
|
|
|
|
|
{
|
|
|
|
let p =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::PointerCast(stack_spill_cx, v, T_ptr(T_opaque_ivec()));
|
2011-08-22 13:48:00 -05:00
|
|
|
let upcall = bcx_ccx(cx).upcalls.ivec_spill_shared;
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Call(stack_spill_cx, upcall,
|
2011-08-22 13:48:00 -05:00
|
|
|
[cx.fcx.lltaskptr, p, new_stack_len]);
|
|
|
|
}
|
|
|
|
let spill_stub =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::PointerCast(stack_spill_cx, v, T_ptr(T_ivec_heap(llunitty)));
|
2011-08-22 13:48:00 -05:00
|
|
|
|
|
|
|
let heap_ptr_spill =
|
|
|
|
load_inbounds(stack_spill_cx, spill_stub, stub_p);
|
|
|
|
|
|
|
|
let heap_data_spill =
|
|
|
|
{
|
|
|
|
let v =
|
|
|
|
[C_int(0), C_uint(abi::ivec_heap_elt_elems),
|
|
|
|
stack_len_unscaled];
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::InBoundsGEP(stack_spill_cx, heap_ptr_spill, v)
|
2011-08-22 13:48:00 -05:00
|
|
|
};
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Br(stack_spill_cx, next_cx.llbb);
|
2011-08-22 13:48:00 -05:00
|
|
|
// Phi together the different data pointers to get the result.
|
|
|
|
|
|
|
|
let data_ptr =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Phi(next_cx, T_ptr(llunitty),
|
2011-08-22 13:48:00 -05:00
|
|
|
[heap_data_no_resize, heap_data_resize,
|
|
|
|
stack_data_no_spill, heap_data_spill],
|
|
|
|
[heap_no_resize_cx.llbb, heap_resize_cx.llbb,
|
|
|
|
stack_no_spill_cx.llbb, stack_spill_cx.llbb]);
|
|
|
|
ret rslt(next_cx, data_ptr);
|
|
|
|
}
|
2011-08-24 06:53:34 -05:00
|
|
|
fn trans_append(cx: &@block_ctxt, t: ty::t, lhs: ValueRef,
|
|
|
|
rhs: ValueRef) -> result {
|
2011-08-22 13:48:00 -05:00
|
|
|
// Cast to opaque interior vector types if necessary.
|
|
|
|
if ty::type_has_dynamic_size(bcx_tcx(cx), t) {
|
2011-08-24 07:54:55 -05:00
|
|
|
lhs = bld::PointerCast(cx, lhs, T_ptr(T_opaque_ivec()));
|
|
|
|
rhs = bld::PointerCast(cx, rhs, T_ptr(T_opaque_ivec()));
|
2011-08-24 06:53:34 -05:00
|
|
|
}
|
2011-08-22 13:48:00 -05:00
|
|
|
|
|
|
|
let unit_ty = ty::sequence_element_type(bcx_tcx(cx), t);
|
|
|
|
let llunitty = type_of_or_i8(cx, unit_ty);
|
|
|
|
|
|
|
|
let rs = size_of(cx, unit_ty);
|
|
|
|
let bcx = rs.bcx;
|
|
|
|
let unit_sz = rs.val;
|
|
|
|
|
|
|
|
// Gather the various type descriptors we'll need.
|
|
|
|
|
|
|
|
// FIXME (issue #511): This is needed to prevent a leak.
|
|
|
|
let no_tydesc_info = none;
|
|
|
|
|
2011-08-24 20:36:51 -05:00
|
|
|
rs = get_tydesc(bcx, t, false, tps_normal, no_tydesc_info).result;
|
2011-08-22 13:48:00 -05:00
|
|
|
bcx = rs.bcx;
|
2011-08-24 20:36:51 -05:00
|
|
|
rs = get_tydesc(bcx, unit_ty, false, tps_normal, no_tydesc_info).result;
|
2011-08-22 13:48:00 -05:00
|
|
|
bcx = rs.bcx;
|
|
|
|
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_take_glue, none);
|
|
|
|
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, none);
|
|
|
|
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, none);
|
2011-08-24 13:30:20 -05:00
|
|
|
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_copy_glue, none);
|
2011-08-22 13:48:00 -05:00
|
|
|
let rhs_len_and_data = get_len_and_data(bcx, rhs, unit_ty);
|
|
|
|
let rhs_len = rhs_len_and_data.len;
|
|
|
|
let rhs_data = rhs_len_and_data.data;
|
|
|
|
bcx = rhs_len_and_data.bcx;
|
2011-08-22 19:35:38 -05:00
|
|
|
|
|
|
|
let have_istrs = alt ty::struct(bcx_tcx(cx), t) {
|
|
|
|
ty::ty_istr. { true }
|
|
|
|
ty::ty_vec(_) { false }
|
2011-08-27 18:36:48 -05:00
|
|
|
_ { bcx_tcx(cx).sess.bug(~"non-istr/ivec in trans_append"); }
|
2011-08-22 19:35:38 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
let extra_len = if have_istrs {
|
|
|
|
// Only need one of the nulls
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Sub(bcx, rhs_len, C_uint(1u))
|
2011-08-22 19:35:38 -05:00
|
|
|
} else { rhs_len };
|
|
|
|
|
|
|
|
rs = reserve_space(bcx, llunitty, lhs, extra_len);
|
2011-08-22 13:48:00 -05:00
|
|
|
bcx = rs.bcx;
|
2011-08-22 17:04:28 -05:00
|
|
|
|
2011-08-22 19:35:38 -05:00
|
|
|
let lhs_data = if have_istrs {
|
|
|
|
let lhs_data = rs.val;
|
|
|
|
let lhs_data_without_null_ptr = alloca(bcx, T_ptr(llunitty));
|
|
|
|
incr_ptr(bcx, lhs_data, C_int(-1),
|
|
|
|
lhs_data_without_null_ptr);
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Load(bcx, lhs_data_without_null_ptr)
|
2011-08-22 19:35:38 -05:00
|
|
|
} else {
|
|
|
|
rs.val
|
|
|
|
};
|
|
|
|
|
2011-08-22 17:04:28 -05:00
|
|
|
// If rhs is lhs then our rhs pointer may have changed
|
|
|
|
rhs_len_and_data = get_len_and_data(bcx, rhs, unit_ty);
|
|
|
|
rhs_data = rhs_len_and_data.data;
|
|
|
|
bcx = rhs_len_and_data.bcx;
|
|
|
|
|
2011-08-22 13:48:00 -05:00
|
|
|
// Work out the end pointer.
|
|
|
|
|
2011-08-24 07:54:55 -05:00
|
|
|
let lhs_unscaled_idx = bld::UDiv(bcx, rhs_len, llsize_of(llunitty));
|
|
|
|
let lhs_end = bld::InBoundsGEP(bcx, lhs_data, [lhs_unscaled_idx]);
|
2011-08-22 13:48:00 -05:00
|
|
|
// Now emit the copy loop.
|
|
|
|
|
|
|
|
let dest_ptr = alloca(bcx, T_ptr(llunitty));
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Store(bcx, lhs_data, dest_ptr);
|
2011-08-22 13:48:00 -05:00
|
|
|
let src_ptr = alloca(bcx, T_ptr(llunitty));
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Store(bcx, rhs_data, src_ptr);
|
2011-08-26 23:34:56 -05:00
|
|
|
let copy_loop_header_cx = new_sub_block_ctxt(bcx, ~"copy_loop_header");
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Br(bcx, copy_loop_header_cx.llbb);
|
|
|
|
let copy_dest_ptr = bld::Load(copy_loop_header_cx, dest_ptr);
|
2011-08-22 13:48:00 -05:00
|
|
|
let not_yet_at_end =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::ICmp(copy_loop_header_cx, lib::llvm::LLVMIntNE,
|
2011-08-22 13:48:00 -05:00
|
|
|
copy_dest_ptr, lhs_end);
|
2011-08-26 23:34:56 -05:00
|
|
|
let copy_loop_body_cx = new_sub_block_ctxt(bcx, ~"copy_loop_body");
|
|
|
|
let next_cx = new_sub_block_ctxt(bcx, ~"next");
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::CondBr(copy_loop_header_cx, not_yet_at_end,
|
2011-08-22 13:48:00 -05:00
|
|
|
copy_loop_body_cx.llbb,
|
|
|
|
next_cx.llbb);
|
|
|
|
|
2011-08-24 07:54:55 -05:00
|
|
|
let copy_src_ptr = bld::Load(copy_loop_body_cx, src_ptr);
|
2011-08-22 13:48:00 -05:00
|
|
|
let copy_src =
|
|
|
|
load_if_immediate(copy_loop_body_cx, copy_src_ptr, unit_ty);
|
|
|
|
|
|
|
|
let post_copy_cx = copy_val
|
|
|
|
(copy_loop_body_cx, INIT, copy_dest_ptr, copy_src, unit_ty);
|
|
|
|
// Increment both pointers.
|
|
|
|
if ty::type_has_dynamic_size(bcx_tcx(cx), t) {
|
|
|
|
// We have to increment by the dynamically-computed size.
|
|
|
|
incr_ptr(post_copy_cx, copy_dest_ptr, unit_sz, dest_ptr);
|
|
|
|
incr_ptr(post_copy_cx, copy_src_ptr, unit_sz, src_ptr);
|
|
|
|
} else {
|
|
|
|
incr_ptr(post_copy_cx, copy_dest_ptr, C_int(1), dest_ptr);
|
|
|
|
incr_ptr(post_copy_cx, copy_src_ptr, C_int(1), src_ptr);
|
|
|
|
}
|
|
|
|
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Br(post_copy_cx, copy_loop_header_cx.llbb);
|
2011-08-22 13:48:00 -05:00
|
|
|
ret rslt(next_cx, C_nil());
|
|
|
|
}
|
|
|
|
|
2011-08-24 06:53:34 -05:00
|
|
|
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;
|
2011-08-24 20:36:51 -05:00
|
|
|
let {bcx, val: td} =
|
|
|
|
get_tydesc(bcx, elt_ty, false, tps_normal, ti).result;
|
2011-08-24 06:53:34 -05:00
|
|
|
trans::lazily_emit_all_tydesc_glue(bcx, ti);
|
2011-08-24 07:54:55 -05:00
|
|
|
let opaque_v = bld::PointerCast(bcx, v, T_ptr(T_opaque_ivec()));
|
2011-08-24 06:53:34 -05:00
|
|
|
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);
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Call(bcx, bcx_ccx(bcx).upcalls.ivec_push,
|
2011-08-24 06:53:34 -05:00
|
|
|
[bcx.fcx.lltaskptr, opaque_v, td,
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::PointerCast(bcx, spilled, T_ptr(T_i8()))]);
|
2011-08-24 06:53:34 -05:00
|
|
|
}
|
|
|
|
ret bcx;
|
|
|
|
}
|
|
|
|
|
2011-08-22 13:48:00 -05:00
|
|
|
type alloc_result =
|
|
|
|
{bcx: @block_ctxt,
|
|
|
|
llptr: ValueRef,
|
|
|
|
llunitsz: ValueRef,
|
|
|
|
llalen: ValueRef};
|
|
|
|
|
|
|
|
fn alloc(cx: &@block_ctxt, unit_ty: ty::t) -> alloc_result {
|
|
|
|
let dynamic = ty::type_has_dynamic_size(bcx_tcx(cx), unit_ty);
|
|
|
|
|
|
|
|
let bcx;
|
|
|
|
if dynamic {
|
|
|
|
bcx = llderivedtydescs_block_ctxt(cx.fcx);
|
|
|
|
} else { bcx = cx; }
|
|
|
|
|
|
|
|
let llunitsz;
|
|
|
|
let rslt = size_of(bcx, unit_ty);
|
|
|
|
bcx = rslt.bcx;
|
|
|
|
llunitsz = rslt.val;
|
|
|
|
|
|
|
|
if dynamic { cx.fcx.llderivedtydescs = bcx.llbb; }
|
|
|
|
|
|
|
|
let llalen =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Mul(bcx, llunitsz, C_uint(abi::ivec_default_length));
|
2011-08-22 13:48:00 -05:00
|
|
|
|
|
|
|
let llptr;
|
|
|
|
let llunitty = type_of_or_i8(bcx, unit_ty);
|
|
|
|
let bcx_result;
|
|
|
|
if dynamic {
|
2011-08-24 07:54:55 -05:00
|
|
|
let llarraysz = bld::Add(bcx, llsize_of(T_opaque_ivec()), llalen);
|
2011-08-22 13:48:00 -05:00
|
|
|
let llvecptr = array_alloca(bcx, T_i8(), llarraysz);
|
|
|
|
|
|
|
|
bcx_result = cx;
|
|
|
|
llptr =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::PointerCast(bcx_result, llvecptr,
|
2011-08-22 13:48:00 -05:00
|
|
|
T_ptr(T_opaque_ivec()));
|
|
|
|
} else { llptr = alloca(bcx, T_ivec(llunitty)); bcx_result = bcx; }
|
|
|
|
|
|
|
|
ret {bcx: bcx_result,
|
|
|
|
llptr: llptr,
|
|
|
|
llunitsz: llunitsz,
|
|
|
|
llalen: llalen};
|
|
|
|
}
|
|
|
|
|
|
|
|
fn trans_add(cx: &@block_ctxt, vec_ty: ty::t, lhs: ValueRef,
|
|
|
|
rhs: ValueRef) -> result {
|
|
|
|
let bcx = cx;
|
|
|
|
let unit_ty = ty::sequence_element_type(bcx_tcx(bcx), vec_ty);
|
|
|
|
|
|
|
|
let ares = alloc(bcx, unit_ty);
|
|
|
|
bcx = ares.bcx;
|
|
|
|
let llvecptr = ares.llptr;
|
|
|
|
let unit_sz = ares.llunitsz;
|
|
|
|
let llalen = ares.llalen;
|
|
|
|
|
|
|
|
add_clean_temp(bcx, llvecptr, vec_ty);
|
|
|
|
|
|
|
|
let llunitty = type_of_or_i8(bcx, unit_ty);
|
|
|
|
let llheappartty = T_ivec_heap_part(llunitty);
|
|
|
|
let lhs_len_and_data = get_len_and_data(bcx, lhs, unit_ty);
|
|
|
|
let lhs_len = lhs_len_and_data.len;
|
|
|
|
let lhs_data = lhs_len_and_data.data;
|
|
|
|
bcx = lhs_len_and_data.bcx;
|
2011-08-22 18:39:18 -05:00
|
|
|
|
|
|
|
lhs_len = alt ty::struct(bcx_tcx(bcx), vec_ty) {
|
|
|
|
ty::ty_istr. {
|
|
|
|
// Forget about the trailing null on the left side
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Sub(bcx, lhs_len, C_uint(1u))
|
2011-08-22 18:39:18 -05:00
|
|
|
}
|
|
|
|
ty::ty_vec(_) { lhs_len }
|
2011-08-27 18:36:48 -05:00
|
|
|
_ { bcx_tcx(bcx).sess.bug(~"non-istr/ivec in trans_add") }
|
2011-08-22 18:39:18 -05:00
|
|
|
};
|
|
|
|
|
2011-08-22 13:48:00 -05:00
|
|
|
let rhs_len_and_data = get_len_and_data(bcx, rhs, unit_ty);
|
|
|
|
let rhs_len = rhs_len_and_data.len;
|
|
|
|
let rhs_data = rhs_len_and_data.data;
|
|
|
|
bcx = rhs_len_and_data.bcx;
|
2011-08-24 07:54:55 -05:00
|
|
|
let lllen = bld::Add(bcx, lhs_len, rhs_len);
|
2011-08-22 13:48:00 -05:00
|
|
|
// We have three cases to handle here:
|
|
|
|
// (1) Length is zero ([] + []).
|
|
|
|
// (2) Copy onto stack.
|
|
|
|
// (3) Allocate on heap and copy there.
|
|
|
|
|
|
|
|
let len_is_zero =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::ICmp(bcx, lib::llvm::LLVMIntEQ, lllen, C_int(0));
|
2011-08-26 23:34:56 -05:00
|
|
|
let zero_len_cx = new_sub_block_ctxt(bcx, ~"zero_len");
|
|
|
|
let nonzero_len_cx = new_sub_block_ctxt(bcx, ~"nonzero_len");
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::CondBr(bcx, len_is_zero, zero_len_cx.llbb, nonzero_len_cx.llbb);
|
2011-08-22 13:48:00 -05:00
|
|
|
// Case (1): Length is zero.
|
|
|
|
|
|
|
|
let stub_z = [C_int(0), C_uint(abi::ivec_heap_stub_elt_zero)];
|
|
|
|
let stub_a = [C_int(0), C_uint(abi::ivec_heap_stub_elt_alen)];
|
|
|
|
let stub_p = [C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)];
|
|
|
|
|
|
|
|
let vec_l = [C_int(0), C_uint(abi::ivec_elt_len)];
|
|
|
|
let vec_a = [C_int(0), C_uint(abi::ivec_elt_alen)];
|
|
|
|
|
|
|
|
let stub_ptr_zero =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::PointerCast(zero_len_cx, llvecptr,
|
2011-08-22 13:48:00 -05:00
|
|
|
T_ptr(T_ivec_heap(llunitty)));
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Store(zero_len_cx, C_int(0),
|
|
|
|
bld::InBoundsGEP(zero_len_cx, stub_ptr_zero,
|
2011-08-22 13:48:00 -05:00
|
|
|
stub_z));
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Store(zero_len_cx, llalen,
|
|
|
|
bld::InBoundsGEP(zero_len_cx, stub_ptr_zero,
|
2011-08-22 13:48:00 -05:00
|
|
|
stub_a));
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Store(zero_len_cx, C_null(T_ptr(llheappartty)),
|
|
|
|
bld::InBoundsGEP(zero_len_cx, stub_ptr_zero,
|
2011-08-22 13:48:00 -05:00
|
|
|
stub_p));
|
2011-08-26 23:34:56 -05:00
|
|
|
let next_cx = new_sub_block_ctxt(bcx, ~"next");
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Br(zero_len_cx, next_cx.llbb);
|
2011-08-22 13:48:00 -05:00
|
|
|
// Determine whether we need to spill to the heap.
|
|
|
|
|
|
|
|
let on_stack =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::ICmp(nonzero_len_cx, lib::llvm::LLVMIntULE, lllen, llalen);
|
2011-08-26 23:34:56 -05:00
|
|
|
let stack_cx = new_sub_block_ctxt(bcx, ~"stack");
|
|
|
|
let heap_cx = new_sub_block_ctxt(bcx, ~"heap");
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::CondBr(nonzero_len_cx, on_stack, stack_cx.llbb, heap_cx.llbb);
|
2011-08-22 13:48:00 -05:00
|
|
|
// Case (2): Copy onto stack.
|
|
|
|
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Store(stack_cx, lllen,
|
|
|
|
bld::InBoundsGEP(stack_cx, llvecptr, vec_l));
|
|
|
|
bld::Store(stack_cx, llalen,
|
|
|
|
bld::InBoundsGEP(stack_cx, llvecptr, vec_a));
|
2011-08-22 13:48:00 -05:00
|
|
|
let dest_ptr_stack =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::InBoundsGEP(stack_cx, llvecptr,
|
2011-08-22 13:48:00 -05:00
|
|
|
[C_int(0), C_uint(abi::ivec_elt_elems),
|
|
|
|
C_int(0)]);
|
2011-08-26 23:34:56 -05:00
|
|
|
let copy_cx = new_sub_block_ctxt(bcx, ~"copy");
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Br(stack_cx, copy_cx.llbb);
|
2011-08-22 13:48:00 -05:00
|
|
|
// Case (3): Allocate on heap and copy there.
|
|
|
|
|
|
|
|
let stub_ptr_heap =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::PointerCast(heap_cx, llvecptr, T_ptr(T_ivec_heap(llunitty)));
|
|
|
|
bld::Store(heap_cx, C_int(0),
|
|
|
|
bld::InBoundsGEP(heap_cx, stub_ptr_heap, stub_z));
|
|
|
|
bld::Store(heap_cx, lllen,
|
|
|
|
bld::InBoundsGEP(heap_cx, stub_ptr_heap, stub_a));
|
|
|
|
let heap_sz = bld::Add(heap_cx, llsize_of(llheappartty), lllen);
|
2011-08-22 13:48:00 -05:00
|
|
|
let rs = trans_shared_malloc(heap_cx, T_ptr(llheappartty), heap_sz);
|
|
|
|
let heap_part = rs.val;
|
|
|
|
heap_cx = rs.bcx;
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Store(heap_cx, heap_part,
|
|
|
|
bld::InBoundsGEP(heap_cx, stub_ptr_heap, stub_p));
|
2011-08-22 13:48:00 -05:00
|
|
|
{
|
|
|
|
let v = [C_int(0), C_uint(abi::ivec_heap_elt_len)];
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Store(heap_cx, lllen,
|
|
|
|
bld::InBoundsGEP(heap_cx, heap_part, v));
|
2011-08-22 13:48:00 -05:00
|
|
|
}
|
|
|
|
let dest_ptr_heap =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::InBoundsGEP(heap_cx, heap_part,
|
2011-08-22 13:48:00 -05:00
|
|
|
[C_int(0),
|
|
|
|
C_uint(abi::ivec_heap_elt_elems),
|
|
|
|
C_int(0)]);
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Br(heap_cx, copy_cx.llbb);
|
2011-08-22 13:48:00 -05:00
|
|
|
// Emit the copy loop.
|
|
|
|
|
|
|
|
let first_dest_ptr =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Phi(copy_cx, T_ptr(llunitty),
|
2011-08-22 13:48:00 -05:00
|
|
|
[dest_ptr_stack, dest_ptr_heap],
|
|
|
|
[stack_cx.llbb, heap_cx.llbb]);
|
|
|
|
|
|
|
|
let lhs_end_ptr;
|
|
|
|
let rhs_end_ptr;
|
|
|
|
if ty::type_has_dynamic_size(bcx_tcx(cx), unit_ty) {
|
2011-08-24 07:54:55 -05:00
|
|
|
lhs_end_ptr = bld::InBoundsGEP(copy_cx, lhs_data, [lhs_len]);
|
|
|
|
rhs_end_ptr = bld::InBoundsGEP(copy_cx, rhs_data, [rhs_len]);
|
2011-08-22 13:48:00 -05:00
|
|
|
} else {
|
2011-08-24 07:54:55 -05:00
|
|
|
let lhs_len_unscaled = bld::UDiv(copy_cx, lhs_len, unit_sz);
|
2011-08-22 13:48:00 -05:00
|
|
|
lhs_end_ptr =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::InBoundsGEP(copy_cx, lhs_data, [lhs_len_unscaled]);
|
|
|
|
let rhs_len_unscaled = bld::UDiv(copy_cx, rhs_len, unit_sz);
|
2011-08-22 13:48:00 -05:00
|
|
|
rhs_end_ptr =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::InBoundsGEP(copy_cx, rhs_data, [rhs_len_unscaled]);
|
2011-08-22 13:48:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
let dest_ptr_ptr = alloca(copy_cx, T_ptr(llunitty));
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Store(copy_cx, first_dest_ptr, dest_ptr_ptr);
|
2011-08-22 13:48:00 -05:00
|
|
|
let lhs_ptr_ptr = alloca(copy_cx, T_ptr(llunitty));
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Store(copy_cx, lhs_data, lhs_ptr_ptr);
|
2011-08-22 13:48:00 -05:00
|
|
|
let rhs_ptr_ptr = alloca(copy_cx, T_ptr(llunitty));
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Store(copy_cx, rhs_data, rhs_ptr_ptr);
|
2011-08-26 23:34:56 -05:00
|
|
|
let lhs_copy_cx = new_sub_block_ctxt(bcx, ~"lhs_copy");
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Br(copy_cx, lhs_copy_cx.llbb);
|
2011-08-22 13:48:00 -05:00
|
|
|
// Copy in elements from the LHS.
|
|
|
|
|
2011-08-24 07:54:55 -05:00
|
|
|
let lhs_ptr = bld::Load(lhs_copy_cx, lhs_ptr_ptr);
|
2011-08-22 13:48:00 -05:00
|
|
|
let not_at_end_lhs =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::ICmp(lhs_copy_cx, lib::llvm::LLVMIntNE, lhs_ptr,
|
2011-08-22 13:48:00 -05:00
|
|
|
lhs_end_ptr);
|
2011-08-26 23:34:56 -05:00
|
|
|
let lhs_do_copy_cx = new_sub_block_ctxt(bcx, ~"lhs_do_copy");
|
|
|
|
let rhs_copy_cx = new_sub_block_ctxt(bcx, ~"rhs_copy");
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::CondBr(lhs_copy_cx, not_at_end_lhs, lhs_do_copy_cx.llbb,
|
2011-08-22 13:48:00 -05:00
|
|
|
rhs_copy_cx.llbb);
|
2011-08-24 07:54:55 -05:00
|
|
|
let dest_ptr_lhs_copy = bld::Load(lhs_do_copy_cx, dest_ptr_ptr);
|
2011-08-22 13:48:00 -05:00
|
|
|
let lhs_val = load_if_immediate(lhs_do_copy_cx, lhs_ptr, unit_ty);
|
|
|
|
lhs_do_copy_cx = copy_val(lhs_do_copy_cx, INIT, dest_ptr_lhs_copy,
|
|
|
|
lhs_val, unit_ty);
|
|
|
|
|
|
|
|
// Increment both pointers.
|
|
|
|
if ty::type_has_dynamic_size(bcx_tcx(cx), unit_ty) {
|
|
|
|
// We have to increment by the dynamically-computed size.
|
|
|
|
incr_ptr(lhs_do_copy_cx, dest_ptr_lhs_copy, unit_sz,
|
|
|
|
dest_ptr_ptr);
|
|
|
|
incr_ptr(lhs_do_copy_cx, lhs_ptr, unit_sz, lhs_ptr_ptr);
|
|
|
|
} else {
|
|
|
|
incr_ptr(lhs_do_copy_cx, dest_ptr_lhs_copy, C_int(1),
|
|
|
|
dest_ptr_ptr);
|
|
|
|
incr_ptr(lhs_do_copy_cx, lhs_ptr, C_int(1), lhs_ptr_ptr);
|
|
|
|
}
|
|
|
|
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Br(lhs_do_copy_cx, lhs_copy_cx.llbb);
|
2011-08-22 13:48:00 -05:00
|
|
|
// Copy in elements from the RHS.
|
|
|
|
|
2011-08-24 07:54:55 -05:00
|
|
|
let rhs_ptr = bld::Load(rhs_copy_cx, rhs_ptr_ptr);
|
2011-08-22 13:48:00 -05:00
|
|
|
let not_at_end_rhs =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::ICmp(rhs_copy_cx, lib::llvm::LLVMIntNE, rhs_ptr,
|
2011-08-22 13:48:00 -05:00
|
|
|
rhs_end_ptr);
|
2011-08-26 23:34:56 -05:00
|
|
|
let rhs_do_copy_cx = new_sub_block_ctxt(bcx, ~"rhs_do_copy");
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::CondBr(rhs_copy_cx, not_at_end_rhs, rhs_do_copy_cx.llbb,
|
2011-08-22 13:48:00 -05:00
|
|
|
next_cx.llbb);
|
2011-08-24 07:54:55 -05:00
|
|
|
let dest_ptr_rhs_copy = bld::Load(rhs_do_copy_cx, dest_ptr_ptr);
|
2011-08-22 13:48:00 -05:00
|
|
|
let rhs_val = load_if_immediate(rhs_do_copy_cx, rhs_ptr, unit_ty);
|
|
|
|
rhs_do_copy_cx = copy_val(rhs_do_copy_cx, INIT, dest_ptr_rhs_copy,
|
|
|
|
rhs_val, unit_ty);
|
|
|
|
|
|
|
|
// Increment both pointers.
|
|
|
|
if ty::type_has_dynamic_size(bcx_tcx(cx), unit_ty) {
|
|
|
|
// We have to increment by the dynamically-computed size.
|
|
|
|
incr_ptr(rhs_do_copy_cx, dest_ptr_rhs_copy, unit_sz,
|
|
|
|
dest_ptr_ptr);
|
|
|
|
incr_ptr(rhs_do_copy_cx, rhs_ptr, unit_sz, rhs_ptr_ptr);
|
|
|
|
} else {
|
|
|
|
incr_ptr(rhs_do_copy_cx, dest_ptr_rhs_copy, C_int(1),
|
|
|
|
dest_ptr_ptr);
|
|
|
|
incr_ptr(rhs_do_copy_cx, rhs_ptr, C_int(1), rhs_ptr_ptr);
|
|
|
|
}
|
|
|
|
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Br(rhs_do_copy_cx, rhs_copy_cx.llbb);
|
2011-08-22 13:48:00 -05:00
|
|
|
// Finally done!
|
|
|
|
|
|
|
|
ret rslt(next_cx, llvecptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// NB: This does *not* adjust reference counts. The caller must have done
|
|
|
|
// this via take_ty() beforehand.
|
|
|
|
fn duplicate_heap_part(cx: &@block_ctxt, orig_vptr: ValueRef,
|
|
|
|
unit_ty: ty::t) -> result {
|
|
|
|
// Cast to an opaque interior vector if we can't trust the pointer
|
|
|
|
// type.
|
|
|
|
let vptr;
|
|
|
|
if ty::type_has_dynamic_size(bcx_tcx(cx), unit_ty) {
|
2011-08-24 07:54:55 -05:00
|
|
|
vptr = bld::PointerCast(cx, orig_vptr, T_ptr(T_opaque_ivec()));
|
2011-08-22 13:48:00 -05:00
|
|
|
} else { vptr = orig_vptr; }
|
|
|
|
|
|
|
|
let llunitty = type_of_or_i8(cx, unit_ty);
|
|
|
|
let llheappartty = T_ivec_heap_part(llunitty);
|
|
|
|
|
|
|
|
// Check to see if the vector is heapified.
|
|
|
|
let stack_len_ptr =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::InBoundsGEP(cx, vptr, [C_int(0), C_uint(abi::ivec_elt_len)]);
|
|
|
|
let stack_len = bld::Load(cx, stack_len_ptr);
|
2011-08-22 13:48:00 -05:00
|
|
|
let stack_len_is_zero =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::ICmp(cx, lib::llvm::LLVMIntEQ, stack_len, C_int(0));
|
2011-08-26 23:34:56 -05:00
|
|
|
let maybe_on_heap_cx = new_sub_block_ctxt(cx, ~"maybe_on_heap");
|
|
|
|
let next_cx = new_sub_block_ctxt(cx, ~"next");
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::CondBr(cx, stack_len_is_zero, maybe_on_heap_cx.llbb,
|
2011-08-22 13:48:00 -05:00
|
|
|
next_cx.llbb);
|
|
|
|
|
|
|
|
let stub_ptr =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::PointerCast(maybe_on_heap_cx, vptr,
|
2011-08-22 13:48:00 -05:00
|
|
|
T_ptr(T_ivec_heap(llunitty)));
|
|
|
|
let heap_ptr_ptr =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::InBoundsGEP(maybe_on_heap_cx,
|
2011-08-22 13:48:00 -05:00
|
|
|
stub_ptr,
|
|
|
|
[C_int(0),
|
|
|
|
C_uint(abi::ivec_heap_stub_elt_ptr)]);
|
2011-08-24 07:54:55 -05:00
|
|
|
let heap_ptr = bld::Load(maybe_on_heap_cx, heap_ptr_ptr);
|
2011-08-22 13:48:00 -05:00
|
|
|
let heap_ptr_is_nonnull =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::ICmp(maybe_on_heap_cx, lib::llvm::LLVMIntNE, heap_ptr,
|
2011-08-22 13:48:00 -05:00
|
|
|
C_null(T_ptr(llheappartty)));
|
2011-08-26 23:34:56 -05:00
|
|
|
let on_heap_cx = new_sub_block_ctxt(cx, ~"on_heap");
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::CondBr(maybe_on_heap_cx, heap_ptr_is_nonnull, on_heap_cx.llbb,
|
2011-08-22 13:48:00 -05:00
|
|
|
next_cx.llbb);
|
|
|
|
|
|
|
|
// Ok, the vector is on the heap. Copy the heap part.
|
|
|
|
let alen_ptr =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::InBoundsGEP(on_heap_cx, stub_ptr,
|
2011-08-22 13:48:00 -05:00
|
|
|
[C_int(0),
|
|
|
|
C_uint(abi::ivec_heap_stub_elt_alen)]);
|
2011-08-24 07:54:55 -05:00
|
|
|
let alen = bld::Load(on_heap_cx, alen_ptr);
|
2011-08-22 13:48:00 -05:00
|
|
|
|
|
|
|
let heap_part_sz =
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Add(on_heap_cx, alen, llsize_of(T_opaque_ivec_heap_part()));
|
2011-08-22 13:48:00 -05:00
|
|
|
let rs =
|
|
|
|
trans_shared_malloc(on_heap_cx, T_ptr(llheappartty),
|
|
|
|
heap_part_sz);
|
|
|
|
on_heap_cx = rs.bcx;
|
|
|
|
let new_heap_ptr = rs.val;
|
|
|
|
|
|
|
|
rs = call_memmove(on_heap_cx, new_heap_ptr, heap_ptr, heap_part_sz);
|
|
|
|
on_heap_cx = rs.bcx;
|
|
|
|
|
2011-08-24 07:54:55 -05:00
|
|
|
bld::Store(on_heap_cx, new_heap_ptr, heap_ptr_ptr);
|
|
|
|
bld::Br(on_heap_cx, next_cx.llbb);
|
2011-08-22 13:48:00 -05:00
|
|
|
|
|
|
|
ret rslt(next_cx, C_nil());
|
|
|
|
}
|
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
|
|
|
|
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
|
|
|
|
// End:
|
|
|
|
//
|