rustc: Implement simple interior vector append translation
This commit is contained in:
parent
a1bb4a4ded
commit
c3bf7d07e9
6 changed files with 305 additions and 35 deletions
|
@ -10,6 +10,7 @@ import trans::T_i32;
|
||||||
import trans::T_int;
|
import trans::T_int;
|
||||||
import trans::T_nil;
|
import trans::T_nil;
|
||||||
import trans::T_opaque_chan_ptr;
|
import trans::T_opaque_chan_ptr;
|
||||||
|
import trans::T_opaque_ivec;
|
||||||
import trans::T_opaque_port_ptr;
|
import trans::T_opaque_port_ptr;
|
||||||
import trans::T_opaque_vec_ptr;
|
import trans::T_opaque_vec_ptr;
|
||||||
import trans::T_ptr;
|
import trans::T_ptr;
|
||||||
|
@ -56,7 +57,9 @@ type upcalls = rec(
|
||||||
ValueRef new_task,
|
ValueRef new_task,
|
||||||
ValueRef start_task,
|
ValueRef start_task,
|
||||||
ValueRef new_thread,
|
ValueRef new_thread,
|
||||||
ValueRef start_thread
|
ValueRef start_thread,
|
||||||
|
ValueRef ivec_resize,
|
||||||
|
ValueRef ivec_spill
|
||||||
);
|
);
|
||||||
|
|
||||||
fn declare_upcalls(type_names tn, ModuleRef llmod) -> @upcalls {
|
fn declare_upcalls(type_names tn, ModuleRef llmod) -> @upcalls {
|
||||||
|
@ -119,7 +122,11 @@ fn declare_upcalls(type_names tn, ModuleRef llmod) -> @upcalls {
|
||||||
new_thread=d("new_thread", [T_ptr(T_i8())], T_taskptr(tn)),
|
new_thread=d("new_thread", [T_ptr(T_i8())], T_taskptr(tn)),
|
||||||
start_thread=d("start_thread", [T_taskptr(tn), T_int(), T_int(),
|
start_thread=d("start_thread", [T_taskptr(tn), T_int(), T_int(),
|
||||||
T_int(), T_size_t()],
|
T_int(), T_size_t()],
|
||||||
T_taskptr(tn))
|
T_taskptr(tn)),
|
||||||
|
ivec_resize=d("ivec_resize", [T_ptr(T_opaque_ivec()), T_int()],
|
||||||
|
T_void()),
|
||||||
|
ivec_spill=d("ivec_spill", [T_ptr(T_opaque_ivec()), T_int()],
|
||||||
|
T_void())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -584,20 +584,29 @@ fn T_opaque_ivec() -> TypeRef {
|
||||||
T_array(T_i8(), abi::ivec_default_size)]); // Body elements
|
T_array(T_i8(), abi::ivec_default_size)]); // Body elements
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interior vector on the heap. Cast to this when the allocated length (second
|
fn T_ivec_heap_part(TypeRef t) -> TypeRef {
|
||||||
// element of T_ivec above) is zero.
|
ret T_struct([T_int(), // Real length
|
||||||
|
T_array(t, 0u)]); // Body elements
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interior vector on the heap, also known as the "stub". Cast to this when
|
||||||
|
// the allocated length (second element of T_ivec above) is zero.
|
||||||
fn T_ivec_heap(TypeRef t) -> TypeRef {
|
fn T_ivec_heap(TypeRef t) -> TypeRef {
|
||||||
ret T_struct([T_int(), // Length (zero)
|
ret T_struct([T_int(), // Length (zero)
|
||||||
T_int(), // Alloc
|
T_int(), // Alloc
|
||||||
T_ptr(T_struct([T_int(), // Real length
|
T_ptr(T_ivec_heap_part(t))]); // Pointer
|
||||||
T_array(t, 0u)]))]); // Body elements
|
}
|
||||||
|
|
||||||
|
fn T_opaque_ivec_heap_part() -> TypeRef {
|
||||||
|
ret T_struct([T_int(), // Real length
|
||||||
|
T_array(T_i8(), 0u)]); // Body elements
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn T_opaque_ivec_heap() -> TypeRef {
|
fn T_opaque_ivec_heap() -> TypeRef {
|
||||||
ret T_struct([T_int(), // Length (zero)
|
ret T_struct([T_int(), // Length (zero)
|
||||||
T_int(), // Alloc
|
T_int(), // Alloc
|
||||||
T_ptr(T_struct([T_int(), // Real length
|
T_ptr(T_opaque_ivec_heap_part())]); // Pointer
|
||||||
T_array(T_i8(), 0u)]))]); // Body elements
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn T_str() -> TypeRef {
|
fn T_str() -> TypeRef {
|
||||||
|
@ -2670,9 +2679,8 @@ fn get_ivec_len_and_data(&@block_ctxt bcx, ValueRef v, ty::t unit_ty) ->
|
||||||
|
|
||||||
auto stack_len = bcx.build.Load(bcx.build.InBoundsGEP(v,
|
auto stack_len = bcx.build.Load(bcx.build.InBoundsGEP(v,
|
||||||
[C_int(0), C_uint(abi::ivec_elt_len)]));
|
[C_int(0), C_uint(abi::ivec_elt_len)]));
|
||||||
auto stack_elem = bcx.build.InBoundsGEP(v, [C_int(0),
|
auto stack_elem = bcx.build.InBoundsGEP(v,
|
||||||
C_uint(abi::ivec_elt_elems),
|
[C_int(0), C_uint(abi::ivec_elt_elems), C_int(0)]);
|
||||||
C_int(0)]);
|
|
||||||
|
|
||||||
auto on_heap = bcx.build.ICmp(lib::llvm::LLVMIntEQ, stack_len, C_int(0));
|
auto on_heap = bcx.build.ICmp(lib::llvm::LLVMIntEQ, stack_len, C_int(0));
|
||||||
|
|
||||||
|
@ -3680,6 +3688,201 @@ fn trans_vec_append(&@block_ctxt cx, &ty::t t,
|
||||||
dst, src, skip_null]));
|
dst, src, skip_null]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns a tuple consisting of a pointer to the length (to be updated), a
|
||||||
|
// pointer to the newly-reserved space, and a block context.
|
||||||
|
fn reserve_ivec_space(&@block_ctxt cx, TypeRef llunitty, ValueRef v,
|
||||||
|
ValueRef len_needed) -> tup(ValueRef, ValueRef, @block_ctxt) {
|
||||||
|
auto stack_len_ptr = cx.build.InBoundsGEP(v, [C_int(0),
|
||||||
|
C_uint(abi::ivec_elt_len)]);
|
||||||
|
auto stack_len = cx.build.Load(stack_len_ptr);
|
||||||
|
auto alen = cx.build.Load(cx.build.InBoundsGEP(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.
|
||||||
|
|
||||||
|
auto maybe_on_heap = cx.build.ICmp(lib::llvm::LLVMIntEQ, stack_len,
|
||||||
|
C_int(0));
|
||||||
|
auto maybe_on_heap_cx = new_sub_block_ctxt(cx, "maybe_on_heap");
|
||||||
|
auto on_stack_cx = new_sub_block_ctxt(cx, "on_stack");
|
||||||
|
cx.build.CondBr(maybe_on_heap, maybe_on_heap_cx.llbb, on_stack_cx.llbb);
|
||||||
|
|
||||||
|
auto next_cx = new_sub_block_ctxt(cx, "next");
|
||||||
|
|
||||||
|
// We're possibly on the heap, unless the vector is zero-length.
|
||||||
|
auto stub_ptr = maybe_on_heap_cx.build.PointerCast(v,
|
||||||
|
T_ptr(T_ivec_heap(llunitty)));
|
||||||
|
auto heap_ptr = maybe_on_heap_cx.build.Load(
|
||||||
|
maybe_on_heap_cx.build.InBoundsGEP(stub_ptr,
|
||||||
|
[C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)]));
|
||||||
|
auto on_heap = maybe_on_heap_cx.build.ICmp(lib::llvm::LLVMIntNE, heap_ptr,
|
||||||
|
C_null(val_ty(heap_ptr)));
|
||||||
|
auto on_heap_cx = new_sub_block_ctxt(cx, "on_heap");
|
||||||
|
maybe_on_heap_cx.build.CondBr(on_heap, on_heap_cx.llbb, on_stack_cx.llbb);
|
||||||
|
|
||||||
|
// We're definitely on the heap. Check whether we need to resize.
|
||||||
|
auto heap_len_ptr = on_heap_cx.build.InBoundsGEP(heap_ptr, [C_int(0),
|
||||||
|
C_int(0)]);
|
||||||
|
auto heap_len = on_heap_cx.build.Load(heap_len_ptr);
|
||||||
|
auto new_heap_len = on_heap_cx.build.Add(heap_len, len_needed);
|
||||||
|
auto heap_no_resize_needed = on_heap_cx.build.ICmp(lib::llvm::LLVMIntULT,
|
||||||
|
new_heap_len, alen);
|
||||||
|
auto heap_no_resize_cx = new_sub_block_ctxt(cx, "heap_no_resize");
|
||||||
|
auto heap_resize_cx = new_sub_block_ctxt(cx, "heap_resize");
|
||||||
|
on_heap_cx.build.CondBr(heap_no_resize_needed, heap_no_resize_cx.llbb,
|
||||||
|
heap_resize_cx.llbb);
|
||||||
|
|
||||||
|
// Case (1): We're on the heap and don't need to resize.
|
||||||
|
auto heap_len_unscaled = heap_no_resize_cx.build.UDiv(heap_len,
|
||||||
|
llsize_of(llunitty));
|
||||||
|
auto heap_data_no_resize = heap_no_resize_cx.build.InBoundsGEP(heap_ptr,
|
||||||
|
[C_int(0), C_uint(abi::ivec_heap_elt_elems), heap_len_unscaled]);
|
||||||
|
heap_no_resize_cx.build.Br(next_cx.llbb);
|
||||||
|
|
||||||
|
// Case (2): We're on the heap and need to resize. This path is rare, so
|
||||||
|
// we delegate to cold glue.
|
||||||
|
heap_resize_cx.build.Call(
|
||||||
|
cx.fcx.lcx.ccx.upcalls.ivec_resize, [
|
||||||
|
cx.fcx.lltaskptr,
|
||||||
|
heap_resize_cx.build.PointerCast(v, T_ptr(T_opaque_ivec())),
|
||||||
|
new_heap_len
|
||||||
|
]);
|
||||||
|
auto heap_ptr_resize = heap_resize_cx.build.Load(
|
||||||
|
heap_resize_cx.build.InBoundsGEP(stub_ptr,
|
||||||
|
[C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)]));
|
||||||
|
auto heap_data_resize = heap_resize_cx.build.InBoundsGEP(heap_ptr_resize,
|
||||||
|
[C_int(0), C_uint(abi::ivec_heap_elt_elems), C_int(0)]);
|
||||||
|
heap_resize_cx.build.Br(next_cx.llbb);
|
||||||
|
|
||||||
|
// We're on the stack. Check whether we need to spill to the heap.
|
||||||
|
auto new_stack_len = on_stack_cx.build.Add(stack_len, len_needed);
|
||||||
|
auto stack_no_spill_needed = on_stack_cx.build.ICmp(lib::llvm::LLVMIntULT,
|
||||||
|
new_stack_len, alen);
|
||||||
|
auto stack_no_spill_cx = new_sub_block_ctxt(cx, "stack_no_spill");
|
||||||
|
auto stack_spill_cx = new_sub_block_ctxt(cx, "stack_spill");
|
||||||
|
on_stack_cx.build.CondBr(stack_no_spill_needed, stack_no_spill_cx.llbb,
|
||||||
|
stack_spill_cx.llbb);
|
||||||
|
|
||||||
|
// Case (3): We're on the stack and don't need to spill.
|
||||||
|
auto stack_len_unscaled = stack_no_spill_cx.build.UDiv(stack_len,
|
||||||
|
llsize_of(llunitty));
|
||||||
|
auto stack_data_no_spill = stack_no_spill_cx.build.InBoundsGEP(v,
|
||||||
|
[C_int(0), C_uint(abi::ivec_elt_elems), stack_len_unscaled]);
|
||||||
|
stack_no_spill_cx.build.Br(next_cx.llbb);
|
||||||
|
|
||||||
|
// Case (4): We're on the stack and need to spill. Like case (2), this
|
||||||
|
// path is rare, so we delegate to cold glue.
|
||||||
|
stack_spill_cx.build.Call(
|
||||||
|
cx.fcx.lcx.ccx.upcalls.ivec_spill, [
|
||||||
|
cx.fcx.lltaskptr,
|
||||||
|
stack_spill_cx.build.PointerCast(v, T_ptr(T_opaque_ivec())),
|
||||||
|
new_stack_len
|
||||||
|
]);
|
||||||
|
auto spill_stub = stack_spill_cx.build.PointerCast(v,
|
||||||
|
T_ptr(T_ivec_heap(llunitty)));
|
||||||
|
auto heap_ptr_spill = stack_spill_cx.build.Load(
|
||||||
|
stack_spill_cx.build.InBoundsGEP(spill_stub,
|
||||||
|
[C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)]));
|
||||||
|
auto heap_len_ptr_spill = stack_spill_cx.build.InBoundsGEP(heap_ptr_spill,
|
||||||
|
[C_int(0), C_uint(abi::ivec_heap_elt_len)]);
|
||||||
|
auto heap_data_spill = stack_spill_cx.build.InBoundsGEP(heap_ptr_spill,
|
||||||
|
[C_int(0), C_uint(abi::ivec_heap_elt_elems), C_int(0)]);
|
||||||
|
|
||||||
|
stack_spill_cx.build.Br(next_cx.llbb);
|
||||||
|
|
||||||
|
// Phi together the different data pointers to get the result.
|
||||||
|
auto len_ptr = next_cx.build.Phi(T_ptr(T_int()),
|
||||||
|
[heap_len_ptr, heap_len_ptr, stack_len_ptr, heap_len_ptr_spill],
|
||||||
|
[heap_no_resize_cx.llbb, heap_resize_cx.llbb, stack_no_spill_cx.llbb,
|
||||||
|
stack_spill_cx.llbb]);
|
||||||
|
auto data_ptr = next_cx.build.Phi(T_ptr(llunitty),
|
||||||
|
[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 tup(len_ptr, data_ptr, next_cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trans_ivec_append(&@block_ctxt cx, &ty::t t, ValueRef lhs, ValueRef rhs)
|
||||||
|
-> result {
|
||||||
|
auto unit_ty = ty::sequence_element_type(cx.fcx.lcx.ccx.tcx, t);
|
||||||
|
auto llunitty = type_of_or_i8(cx, unit_ty);
|
||||||
|
|
||||||
|
auto skip_null;
|
||||||
|
alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
|
||||||
|
case (ty::ty_istr) { skip_null = true; }
|
||||||
|
case (ty::ty_ivec(_)) { skip_null = false; }
|
||||||
|
case (_) {
|
||||||
|
cx.fcx.lcx.ccx.tcx.sess.bug("non-istr/ivec in trans_ivec_append");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gather the various type descriptors we'll need.
|
||||||
|
auto rslt = get_tydesc(cx, t, false, none);
|
||||||
|
auto vec_tydesc = rslt.val;
|
||||||
|
auto bcx = rslt.bcx;
|
||||||
|
|
||||||
|
rslt = get_tydesc(bcx, unit_ty, false, none);
|
||||||
|
auto unit_tydesc = rslt.val;
|
||||||
|
bcx = rslt.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);
|
||||||
|
|
||||||
|
auto rhs_len_and_data = get_ivec_len_and_data(bcx, rhs, unit_ty);
|
||||||
|
auto rhs_len = rhs_len_and_data._0;
|
||||||
|
auto rhs_data = rhs_len_and_data._1;
|
||||||
|
bcx = rhs_len_and_data._2;
|
||||||
|
|
||||||
|
auto lhs_len_ptr_and_data =
|
||||||
|
reserve_ivec_space(bcx, llunitty, lhs, rhs_len);
|
||||||
|
auto lhs_len_ptr = lhs_len_ptr_and_data._0;
|
||||||
|
auto lhs_data = lhs_len_ptr_and_data._1;
|
||||||
|
bcx = lhs_len_ptr_and_data._2;
|
||||||
|
|
||||||
|
// Work out the end pointer.
|
||||||
|
auto lhs_unscaled_idx = bcx.build.UDiv(rhs_len, llsize_of(llunitty));
|
||||||
|
auto lhs_end = bcx.build.InBoundsGEP(lhs_data, [lhs_unscaled_idx]);
|
||||||
|
|
||||||
|
// Now emit the copy loop.
|
||||||
|
auto dest_ptr = alloca(bcx, T_ptr(llunitty));
|
||||||
|
bcx.build.Store(lhs_data, dest_ptr);
|
||||||
|
auto src_ptr = alloca(bcx, T_ptr(llunitty));
|
||||||
|
bcx.build.Store(rhs_data, src_ptr);
|
||||||
|
|
||||||
|
auto copy_loop_header_cx = new_sub_block_ctxt(bcx, "copy_loop_header");
|
||||||
|
bcx.build.Br(copy_loop_header_cx.llbb);
|
||||||
|
|
||||||
|
auto copy_dest_ptr = copy_loop_header_cx.build.Load(dest_ptr);
|
||||||
|
auto not_yet_at_end = copy_loop_header_cx.build.ICmp(lib::llvm::LLVMIntNE,
|
||||||
|
copy_dest_ptr, lhs_end);
|
||||||
|
auto copy_loop_body_cx = new_sub_block_ctxt(bcx, "copy_loop_body");
|
||||||
|
auto next_cx = new_sub_block_ctxt(bcx, "next");
|
||||||
|
copy_loop_header_cx.build.CondBr(not_yet_at_end, copy_loop_body_cx.llbb,
|
||||||
|
next_cx.llbb);
|
||||||
|
|
||||||
|
auto copy_src_ptr = copy_loop_body_cx.build.Load(src_ptr);
|
||||||
|
rslt = copy_val(copy_loop_body_cx, INIT, copy_dest_ptr, copy_src_ptr, t);
|
||||||
|
auto post_copy_cx = rslt.bcx;
|
||||||
|
|
||||||
|
// Increment both pointers.
|
||||||
|
post_copy_cx.build.Store(post_copy_cx.build.InBoundsGEP(copy_dest_ptr,
|
||||||
|
[C_int(1)]), dest_ptr);
|
||||||
|
post_copy_cx.build.Store(post_copy_cx.build.InBoundsGEP(copy_src_ptr,
|
||||||
|
[C_int(1)]), src_ptr);
|
||||||
|
post_copy_cx.build.Br(copy_loop_header_cx.llbb);
|
||||||
|
|
||||||
|
// Write in the new length.
|
||||||
|
auto new_len = next_cx.build.Add(next_cx.build.Load(lhs_len_ptr),
|
||||||
|
rhs_len);
|
||||||
|
next_cx.build.Store(new_len, lhs_len_ptr);
|
||||||
|
|
||||||
|
ret res(next_cx, C_nil());
|
||||||
|
}
|
||||||
|
|
||||||
fn trans_vec_add(&@block_ctxt cx, &ty::t t,
|
fn trans_vec_add(&@block_ctxt cx, &ty::t t,
|
||||||
ValueRef lhs, ValueRef rhs) -> result {
|
ValueRef lhs, ValueRef rhs) -> result {
|
||||||
auto r = alloc_ty(cx, t);
|
auto r = alloc_ty(cx, t);
|
||||||
|
@ -4741,14 +4944,8 @@ fn trans_index(&@block_ctxt cx, &span sp, &@ast::expr base,
|
||||||
auto base_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, base);
|
auto base_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, base);
|
||||||
auto base_ty_no_boxes = ty::strip_boxes(cx.fcx.lcx.ccx.tcx, base_ty);
|
auto base_ty_no_boxes = ty::strip_boxes(cx.fcx.lcx.ccx.tcx, base_ty);
|
||||||
|
|
||||||
auto is_interior;
|
auto is_interior = ty::sequence_is_interior(cx.fcx.lcx.ccx.tcx,
|
||||||
alt (ty::struct(cx.fcx.lcx.ccx.tcx, base_ty_no_boxes)) {
|
base_ty_no_boxes);
|
||||||
// TODO: Or-patterns
|
|
||||||
case (ty::ty_vec(_)) { is_interior = false; }
|
|
||||||
case (ty::ty_str) { is_interior = false; }
|
|
||||||
case (ty::ty_ivec(_)) { is_interior = true; }
|
|
||||||
case (ty::ty_istr) { is_interior = true; }
|
|
||||||
};
|
|
||||||
|
|
||||||
auto lv = trans_expr(cx, base);
|
auto lv = trans_expr(cx, base);
|
||||||
lv = autoderef(lv.bcx, lv.val, base_ty);
|
lv = autoderef(lv.bcx, lv.val, base_ty);
|
||||||
|
@ -5655,28 +5852,31 @@ fn trans_ivec(@block_ctxt bcx, &vec[@ast::expr] args, &ast::ann ann)
|
||||||
auto llfirsteltptr;
|
auto llfirsteltptr;
|
||||||
if (vec::len(args) > 0u && vec::len(args) < abi::ivec_default_size) {
|
if (vec::len(args) > 0u && vec::len(args) < abi::ivec_default_size) {
|
||||||
// Interior case.
|
// Interior case.
|
||||||
bcx.build.Store(lllen, bcx.build.GEP(llvecptr,
|
bcx.build.Store(lllen, bcx.build.InBoundsGEP(llvecptr,
|
||||||
[C_int(0), C_uint(abi::ivec_elt_len)]));
|
[C_int(0), C_uint(abi::ivec_elt_len)]));
|
||||||
bcx.build.Store(C_uint(abi::ivec_elt_alen), bcx.build.GEP(llvecptr,
|
bcx.build.Store(C_uint(abi::ivec_default_size),
|
||||||
[C_int(0), C_uint(abi::ivec_elt_alen)]));
|
bcx.build.InBoundsGEP(llvecptr,
|
||||||
llfirsteltptr = bcx.build.GEP(llvecptr,
|
[C_int(0), C_uint(abi::ivec_elt_alen)]));
|
||||||
|
llfirsteltptr = bcx.build.InBoundsGEP(llvecptr,
|
||||||
[C_int(0), C_uint(abi::ivec_elt_elems), C_int(0)]);
|
[C_int(0), C_uint(abi::ivec_elt_elems), C_int(0)]);
|
||||||
} else {
|
} else {
|
||||||
// Heap case.
|
// Heap case.
|
||||||
auto llstubty = T_ivec_heap(llunitty);
|
auto llstubty = T_ivec_heap(llunitty);
|
||||||
auto llstubptr = bcx.build.PointerCast(llvecptr, T_ptr(llstubty));
|
auto llstubptr = bcx.build.PointerCast(llvecptr, T_ptr(llstubty));
|
||||||
|
|
||||||
bcx.build.Store(C_int(0), bcx.build.GEP(llstubptr,
|
bcx.build.Store(C_int(0), bcx.build.InBoundsGEP(llstubptr,
|
||||||
[C_int(0), C_uint(abi::ivec_heap_stub_elt_zero)]));
|
[C_int(0), C_uint(abi::ivec_heap_stub_elt_zero)]));
|
||||||
bcx.build.Store(C_uint(abi::ivec_elt_alen), bcx.build.GEP(llstubptr,
|
bcx.build.Store(lllen,
|
||||||
[C_int(0), C_uint(abi::ivec_heap_stub_elt_alen)]));
|
bcx.build.InBoundsGEP(llstubptr,
|
||||||
|
[C_int(0), C_uint(abi::ivec_heap_stub_elt_alen)]));
|
||||||
|
|
||||||
auto llheapty = struct_elt(llstubty, abi::ivec_heap_stub_elt_ptr);
|
auto llheapty = struct_elt(llstubty, abi::ivec_heap_stub_elt_ptr);
|
||||||
|
|
||||||
if (vec::len(args) == 0u) {
|
if (vec::len(args) == 0u) {
|
||||||
// Null heap pointer indicates a zero-length vector.
|
// Null heap pointer indicates a zero-length vector.
|
||||||
bcx.build.Store(C_null(T_ptr(llheapty)), bcx.build.GEP(llstubptr,
|
bcx.build.Store(C_null(T_ptr(llheapty)),
|
||||||
[C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)]));
|
bcx.build.InBoundsGEP(llstubptr,
|
||||||
|
[C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)]));
|
||||||
llfirsteltptr = C_null(T_ptr(llunitty));
|
llfirsteltptr = C_null(T_ptr(llunitty));
|
||||||
} else {
|
} else {
|
||||||
auto llheapsz = bcx.build.Add(llsize_of(llheapty), lllen);
|
auto llheapsz = bcx.build.Add(llsize_of(llheapty), lllen);
|
||||||
|
@ -5684,11 +5884,11 @@ fn trans_ivec(@block_ctxt bcx, &vec[@ast::expr] args, &ast::ann ann)
|
||||||
bcx = rslt.bcx;
|
bcx = rslt.bcx;
|
||||||
auto llheapptr = rslt.val;
|
auto llheapptr = rslt.val;
|
||||||
|
|
||||||
bcx.build.Store(llheapptr, bcx.build.GEP(llstubptr,
|
bcx.build.Store(llheapptr, bcx.build.InBoundsGEP(llstubptr,
|
||||||
[C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)]));
|
[C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)]));
|
||||||
bcx.build.Store(lllen, bcx.build.GEP(llheapptr,
|
bcx.build.Store(lllen, bcx.build.InBoundsGEP(llheapptr,
|
||||||
[C_int(0), C_uint(abi::ivec_heap_elt_len)]));
|
[C_int(0), C_uint(abi::ivec_heap_elt_len)]));
|
||||||
llfirsteltptr = bcx.build.GEP(llheapptr,
|
llfirsteltptr = bcx.build.InBoundsGEP(llheapptr,
|
||||||
[C_int(0), C_uint(abi::ivec_heap_elt_elems), C_int(0)]);
|
[C_int(0), C_uint(abi::ivec_heap_elt_elems), C_int(0)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5864,6 +6064,11 @@ fn trans_expr_out(&@block_ctxt cx, &@ast::expr e, out_method output)
|
||||||
if (ty::type_is_sequence(cx.fcx.lcx.ccx.tcx, t)) {
|
if (ty::type_is_sequence(cx.fcx.lcx.ccx.tcx, t)) {
|
||||||
alt (op) {
|
alt (op) {
|
||||||
case (ast::add) {
|
case (ast::add) {
|
||||||
|
if (ty::sequence_is_interior(cx.fcx.lcx.ccx.tcx, t)) {
|
||||||
|
ret trans_ivec_append(rhs_res.bcx, t,
|
||||||
|
lhs_res.res.val,
|
||||||
|
rhs_res.val);
|
||||||
|
}
|
||||||
ret trans_vec_append(rhs_res.bcx, t,
|
ret trans_vec_append(rhs_res.bcx, t,
|
||||||
lhs_res.res.val,
|
lhs_res.res.val,
|
||||||
rhs_res.val);
|
rhs_res.val);
|
||||||
|
|
|
@ -763,6 +763,19 @@ fn type_is_sequence(&ctxt cx, &t ty) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sequence_is_interior(&ctxt cx, &t ty) -> bool {
|
||||||
|
alt (struct(cx, ty)) {
|
||||||
|
// TODO: Or-patterns
|
||||||
|
case (ty::ty_vec(_)) { ret false; }
|
||||||
|
case (ty::ty_str) { ret false; }
|
||||||
|
case (ty::ty_ivec(_)) { ret true; }
|
||||||
|
case (ty::ty_istr) { ret true; }
|
||||||
|
case (_) {
|
||||||
|
cx.sess.bug("sequence_is_interior called on non-sequence type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn sequence_element_type(&ctxt cx, &t ty) -> t {
|
fn sequence_element_type(&ctxt cx, &t ty) -> t {
|
||||||
alt (struct(cx, ty)) {
|
alt (struct(cx, ty)) {
|
||||||
case (ty_str) { ret mk_mach(cx, common::ty_u8); }
|
case (ty_str) { ret mk_mach(cx, common::ty_u8); }
|
||||||
|
|
|
@ -574,6 +574,25 @@ upcall_start_thread(rust_task *task,
|
||||||
return child_task_proxy;
|
return child_task_proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resizes an interior vector that has been spilled to the heap.
|
||||||
|
*/
|
||||||
|
extern "C" CDECL void
|
||||||
|
upcall_ivec_resize(rust_task *task,
|
||||||
|
rust_ivec *v,
|
||||||
|
size_t newsz) {
|
||||||
|
// TODO
|
||||||
|
task->fail(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" CDECL void
|
||||||
|
upcall_ivec_spill(rust_task *task,
|
||||||
|
rust_ivec *v,
|
||||||
|
size_t newsz) {
|
||||||
|
// TODO
|
||||||
|
task->fail(4);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Local Variables:
|
// Local Variables:
|
||||||
// mode: C++
|
// mode: C++
|
||||||
|
|
|
@ -185,6 +185,30 @@ rust_vec : public rc_base<rust_vec>
|
||||||
// Rust types vec and str look identical from our perspective.
|
// Rust types vec and str look identical from our perspective.
|
||||||
typedef rust_vec rust_str;
|
typedef rust_vec rust_str;
|
||||||
|
|
||||||
|
// Interior vectors (rust-user-code level).
|
||||||
|
|
||||||
|
struct
|
||||||
|
rust_ivec_heap
|
||||||
|
{
|
||||||
|
size_t fill;
|
||||||
|
uint8_t data[];
|
||||||
|
};
|
||||||
|
|
||||||
|
union
|
||||||
|
rust_ivec_payload
|
||||||
|
{
|
||||||
|
uint8_t data[]; // if on stack
|
||||||
|
struct rust_ivec_heap *ptr; // if on heap
|
||||||
|
};
|
||||||
|
|
||||||
|
struct
|
||||||
|
rust_ivec
|
||||||
|
{
|
||||||
|
size_t fill; // in bytes; if zero, heapified
|
||||||
|
size_t alloc; // in bytes
|
||||||
|
rust_ivec_payload payload;
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// Local Variables:
|
// Local Variables:
|
||||||
// mode: C++
|
// mode: C++
|
||||||
|
|
|
@ -49,6 +49,8 @@ upcall_flush_chan
|
||||||
upcall_free
|
upcall_free
|
||||||
upcall_get_type_desc
|
upcall_get_type_desc
|
||||||
upcall_grow_task
|
upcall_grow_task
|
||||||
|
upcall_ivec_resize
|
||||||
|
upcall_ivec_spill
|
||||||
upcall_join
|
upcall_join
|
||||||
upcall_kill
|
upcall_kill
|
||||||
upcall_log_double
|
upcall_log_double
|
||||||
|
|
Loading…
Reference in a new issue