rustc: Copy the contents of generic interior vectors

This commit is contained in:
Patrick Walton 2011-06-17 12:03:40 -07:00
parent 4bb7597542
commit 4918c99f69
2 changed files with 73 additions and 83 deletions

View File

@ -1321,6 +1321,15 @@ fn dynamic_size_of(&@block_ctxt cx, ty::t t) -> result {
auto total_size = bcx.build.Add(max_size_val, llsize_of(T_int()));
ret res(bcx, total_size);
}
case (ty::ty_ivec(?mt)) {
auto rslt = field_of_tydesc(cx, mt.ty, false,
abi::tydesc_field_size);
auto bcx = rslt.bcx;
auto llunitszptr = rslt.val;
auto llunitsz = bcx.build.Load(llunitszptr);
auto llsz = bcx.build.Add(llsize_of(T_opaque_ivec()), llunitsz);
ret res(bcx, llsz);
}
}
}
@ -1353,7 +1362,13 @@ fn dynamic_align_of(&@block_ctxt cx, &ty::t t) -> result {
}
case (ty::ty_tag(_, _)) {
ret res(cx, C_int(1)); // FIXME: stub
}
case (ty::ty_ivec(?tm)) {
auto rslt = align_of(cx, tm.ty);
auto bcx = rslt.bcx;
auto llunitalign = rslt.val;
auto llalign = umax(bcx, llalign_of(T_int()), llunitalign);
ret res(bcx, llalign);
}
}
}
@ -2044,8 +2059,15 @@ fn make_drop_glue(&@block_ctxt cx, ValueRef v0, &ty::t t) {
case (ty::ty_str) { rslt = decr_refcnt_maybe_free(cx, v0, v0, t); }
case (ty::ty_vec(_)) { rslt = decr_refcnt_maybe_free(cx, v0, v0, t); }
case (ty::ty_ivec(?tm)) {
rslt = iter_structural_ty(cx, v0, t, drop_ty);
rslt = maybe_free_ivec_heap_part(rslt.bcx, v0, tm.ty);
auto v1;
if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, tm.ty)) {
v1 = cx.build.PointerCast(v0, T_ptr(T_opaque_ivec()));
} else {
v1 = v0;
}
rslt = iter_structural_ty(cx, v1, t, drop_ty);
rslt = maybe_free_ivec_heap_part(rslt.bcx, v1, tm.ty);
}
case (ty::ty_box(_)) { rslt = decr_refcnt_maybe_free(cx, v0, v0, t); }
case (ty::ty_port(_)) {
@ -2396,74 +2418,6 @@ fn make_numerical_cmp_glue(&@block_ctxt cx, ValueRef lhs, ValueRef rhs,
}
// Returns the length of an interior vector and a pointer to its first
// element, in that order.
fn get_len_and_data(&@block_ctxt bcx, ValueRef v, ty::t unit_ty) ->
tup(ValueRef, ValueRef, @block_ctxt) {
auto llunitty = type_of_or_i8(bcx, unit_ty);
auto stack_len =
bcx.build.Load(bcx.build.InBoundsGEP(v,
[C_int(0),
C_uint(abi::ivec_elt_len)]));
auto stack_elem =
bcx.build.InBoundsGEP(v,
[C_int(0), C_uint(abi::ivec_elt_elems),
C_int(0)]);
auto on_heap = bcx.build.ICmp(lib::llvm::LLVMIntEQ, stack_len, C_int(0));
auto on_heap_cx = new_sub_block_ctxt(bcx, "on_heap");
auto next_cx = new_sub_block_ctxt(bcx, "next");
bcx.build.CondBr(on_heap, on_heap_cx.llbb, next_cx.llbb);
auto heap_stub =
on_heap_cx.build.PointerCast(v, T_ptr(T_ivec_heap(llunitty)));
auto heap_ptr =
{
auto v = [C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)];
on_heap_cx.build.Load(on_heap_cx.build.InBoundsGEP(heap_stub, v))
};
// Check whether the heap pointer is null. If it is, the vector length is
// truly zero.
auto llstubty = T_ivec_heap(llunitty);
auto llheapptrty = struct_elt(llstubty, abi::ivec_heap_stub_elt_ptr);
auto heap_ptr_is_null =
on_heap_cx.build.ICmp(lib::llvm::LLVMIntEQ, heap_ptr,
C_null(T_ptr(llheapptrty)));
auto zero_len_cx = new_sub_block_ctxt(bcx, "zero_len");
auto nonzero_len_cx = new_sub_block_ctxt(bcx, "nonzero_len");
on_heap_cx.build.CondBr(heap_ptr_is_null, zero_len_cx.llbb,
nonzero_len_cx.llbb);
// Technically this context is unnecessary, but it makes this function
// clearer.
auto zero_len = C_int(0);
auto zero_elem = C_null(T_ptr(llunitty));
zero_len_cx.build.Br(next_cx.llbb);
// If we're here, then we actually have a heapified vector.
auto heap_len =
{
auto v = [C_int(0), C_uint(abi::ivec_heap_elt_len)];
auto m = nonzero_len_cx.build.InBoundsGEP(heap_ptr, v);
nonzero_len_cx.build.Load(m)
};
auto heap_elem =
nonzero_len_cx.build.InBoundsGEP(heap_ptr,
[C_int(0),
C_uint(abi::ivec_heap_elt_elems),
C_int(0)]);
nonzero_len_cx.build.Br(next_cx.llbb);
// Now we can figure out the length of `v` and get a pointer to its first
// element.
auto len =
next_cx.build.Phi(T_int(), [stack_len, zero_len, heap_len],
[bcx.llbb, zero_len_cx.llbb, nonzero_len_cx.llbb]);
auto elem =
next_cx.build.Phi(T_ptr(llunitty), [stack_elem, zero_elem, heap_elem],
[bcx.llbb, zero_len_cx.llbb, nonzero_len_cx.llbb]);
ret tup(len, elem, next_cx);
}
type val_pair_fn = fn(&@block_ctxt, ValueRef, ValueRef) -> result ;
type val_and_ty_fn = fn(&@block_ctxt, ValueRef, ty::t) -> result ;
@ -3017,8 +2971,10 @@ fn memmove_ty(&@block_ctxt cx, ValueRef dst, ValueRef src, &ty::t t) ->
tag copy_action { INIT; DROP_EXISTING; }
// FIXME: This should copy the contents of the heap part for ivecs.
fn copy_val(&@block_ctxt cx, copy_action action, ValueRef dst, ValueRef src,
&ty::t t) -> result {
if (ty::type_is_scalar(cx.fcx.lcx.ccx.tcx, t) ||
ty::type_is_native(cx.fcx.lcx.ccx.tcx, t)) {
ret res(cx, cx.build.Store(src, dst));
@ -3245,8 +3201,18 @@ mod ivec {
// Returns the length of an interior vector and a pointer to its first
// element, in that order.
fn get_len_and_data(&@block_ctxt bcx, ValueRef v, ty::t unit_ty) ->
tup(ValueRef, ValueRef, @block_ctxt) {
fn get_len_and_data(&@block_ctxt bcx, ValueRef orig_v, ty::t unit_ty)
-> tup(ValueRef, ValueRef, @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.
auto v;
if (ty::type_has_dynamic_size(bcx.fcx.lcx.ccx.tcx, unit_ty)) {
v = bcx.build.PointerCast(orig_v, T_ptr(T_opaque_ivec()));
} else {
v = orig_v;
}
auto llunitty = type_of_or_i8(bcx, unit_ty);
auto stack_len =
{
@ -4715,7 +4681,7 @@ fn trans_index(&@block_ctxt cx, &span sp, &@ast::expr base, &@ast::expr idx,
maybe_name_value(cx.fcx.lcx.ccx, scaled_ix, "scaled_ix");
auto interior_len_and_data;
if (is_interior) {
auto rslt = get_len_and_data(bcx, v, unit_ty);
auto rslt = ivec::get_len_and_data(bcx, v, unit_ty);
interior_len_and_data = some(tup(rslt._0, rslt._1));
bcx = rslt._2;
} else { interior_len_and_data = none; }

View File

@ -883,12 +883,38 @@ fn type_is_native(&ctxt cx, &t ty) -> bool {
fn type_has_dynamic_size(&ctxt cx, &t ty) -> bool {
alt (struct(cx, ty)) {
case (ty_nil) { ret false; }
case (ty_bot) { ret false; }
case (ty_bool) { ret false; }
case (ty_int) { ret false; }
case (ty_float) { ret false; }
case (ty_uint) { ret false; }
case (ty_machine(_)) { ret false; }
case (ty_char) { ret false; }
case (ty_str) { ret false; }
case (ty_istr) { ret false; }
case (ty_tag(_, ?subtys)) {
auto i = 0u;
while (i < vec::len[t](subtys)) {
if (type_has_dynamic_size(cx, subtys.(i))) { ret true; }
i += 1u;
}
ret false;
}
case (ty_box(_)) { ret false; }
case (ty_vec(_)) { ret false; }
case (ty_ivec(?mt)) { ret type_has_dynamic_size(cx, mt.ty); }
case (ty_ptr(_)) { ret false; }
case (ty_port(_)) { ret false; }
case (ty_chan(_)) { ret false; }
case (ty_task) { ret false; }
case (ty_tup(?mts)) {
auto i = 0u;
while (i < vec::len[mt](mts)) {
if (type_has_dynamic_size(cx, mts.(i).ty)) { ret true; }
i += 1u;
}
ret false;
}
case (ty_rec(?fields)) {
auto i = 0u;
@ -896,18 +922,16 @@ fn type_has_dynamic_size(&ctxt cx, &t ty) -> bool {
if (type_has_dynamic_size(cx, fields.(i).mt.ty)) { ret true; }
i += 1u;
}
ret false;
}
case (ty_tag(_, ?subtys)) {
auto i = 0u;
while (i < vec::len[t](subtys)) {
if (type_has_dynamic_size(cx, subtys.(i))) { ret true; }
i += 1u;
}
}
case (ty_fn(_,_,_,_,_)) { ret false; }
case (ty_native_fn(_,_,_)) { ret false; }
case (ty_obj(_)) { ret false; }
case (ty_var(_)) { fail "ty_var in type_has_dynamic_size()"; }
case (ty_param(_)) { ret true; }
case (_) {/* fall through */ }
case (ty_type) { ret false; }
case (ty_native) { ret false; }
}
ret false;
}
fn type_is_integral(&ctxt cx, &t ty) -> bool {