Skip to content

Commit 00eb3f5

Browse files
committed
rustc: Sketch out translation of interior vector literals and take/drop glue
1 parent b0a8010 commit 00eb3f5

File tree

3 files changed

+251
-23
lines changed

3 files changed

+251
-23
lines changed

src/comp/back/abi.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,17 @@ const int closure_elt_target = 1;
6666
const int closure_elt_bindings = 2;
6767
const int closure_elt_ty_params = 3;
6868

69+
const uint ivec_default_size = 16u;
70+
71+
const uint ivec_elt_len = 0u;
72+
const uint ivec_elt_alen = 1u;
73+
const uint ivec_elt_elems = 2u;
74+
const uint ivec_heap_stub_elt_zero = 0u;
75+
const uint ivec_heap_stub_elt_alen = 1u;
76+
const uint ivec_heap_stub_elt_ptr = 2u;
77+
const uint ivec_heap_elt_len = 0u;
78+
const uint ivec_heap_elt_elems = 1u;
79+
6980

7081
const int worst_case_glue_call_args = 7;
7182

src/comp/middle/trans.rs

Lines changed: 223 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -572,22 +572,28 @@ fn T_opaque_vec_ptr() -> TypeRef {
572572
// Interior vector.
573573
//
574574
// TODO: Support user-defined vector sizes.
575-
fn T_ivec(TypeRef t) -> TypeRef {
576-
ret T_struct([T_int(), // Length ("fill")
577-
T_int(), // Alloc (if zero, it's heapified)
578-
T_array(t, 16u) // Body elements
579-
]);
575+
fn T_ivec() -> TypeRef {
576+
ret T_struct([T_int(), // Length ("fill"; if zero, heapified)
577+
T_int(), // Alloc
578+
T_array(T_i8(), abi::ivec_default_size)]); // Body elements
580579
}
581580

582581
// Interior vector on the heap. Cast to this when the allocated length (second
583582
// element of T_ivec above) is zero.
584583
fn T_ivec_heap(TypeRef t) -> TypeRef {
585-
ret T_struct([T_int(), // Length ("fill")
586-
T_int(), // Alloc (zero in this case)
587-
T_ptr(T_struct([T_int(), // Real alloc
584+
ret T_struct([T_int(), // Length (zero)
585+
T_int(), // Alloc
586+
T_ptr(T_struct([T_int(), // Real length
588587
T_array(t, 0u)]))]); // Body elements
589588
}
590589

590+
fn T_opaque_ivec_heap() -> TypeRef {
591+
ret T_struct([T_int(), // Length (zero)
592+
T_int(), // Alloc
593+
T_ptr(T_struct([T_int(), // Real length
594+
T_array(T_i8(), 0u)]))]); // Body elements
595+
}
596+
591597
fn T_str() -> TypeRef {
592598
ret T_vec(T_i8());
593599
}
@@ -862,7 +868,7 @@ fn type_of_inner(&@crate_ctxt cx, &span sp, &ty::t t) -> TypeRef {
862868
}
863869
case (ty::ty_char) { llty = T_char(); }
864870
case (ty::ty_str) { llty = T_ptr(T_str()); }
865-
case (ty::ty_istr) { llty = T_ivec(T_i8()); }
871+
case (ty::ty_istr) { llty = T_ivec(); }
866872
case (ty::ty_tag(_, _)) {
867873
if (ty::type_has_dynamic_size(cx.tcx, t)) {
868874
llty = T_opaque_tag(cx.tn);
@@ -878,7 +884,7 @@ fn type_of_inner(&@crate_ctxt cx, &span sp, &ty::t t) -> TypeRef {
878884
llty = T_ptr(T_vec(type_of_inner(cx, sp, mt.ty)));
879885
}
880886
case (ty::ty_ivec(?mt)) {
881-
llty = T_ivec(type_of_inner(cx, sp, mt.ty));
887+
llty = T_ivec();
882888
}
883889
case (ty::ty_ptr(?mt)) {
884890
llty = T_ptr(type_of_inner(cx, sp, mt.ty));
@@ -989,6 +995,13 @@ fn type_of_ty_param_count_and_ty(@local_ctxt lcx, &span sp,
989995
ret type_of(lcx.ccx, sp, tpt._1);
990996
}
991997

998+
fn type_of_or_i8(&@block_ctxt bcx, ty::t typ) -> TypeRef {
999+
if (ty::type_has_dynamic_size(bcx.fcx.lcx.ccx.tcx, typ)) {
1000+
ret T_i8();
1001+
}
1002+
ret type_of(bcx.fcx.lcx.ccx, bcx.sp, typ);
1003+
}
1004+
9921005

9931006
// Name sanitation. LLVM will happily accept identifiers with weird names, but
9941007
// gas doesn't!
@@ -1058,6 +1071,10 @@ fn C_int(int i) -> ValueRef {
10581071
ret C_integral(T_int(), i as uint, True);
10591072
}
10601073

1074+
fn C_uint(uint i) -> ValueRef {
1075+
ret C_integral(T_int(), i, False);
1076+
}
1077+
10611078
fn C_u8(uint i) -> ValueRef {
10621079
ret C_integral(T_i8(), i, False);
10631080
}
@@ -2635,6 +2652,64 @@ fn make_numerical_cmp_glue(&@block_ctxt cx, ValueRef lhs, ValueRef rhs,
26352652
r.bcx.build.RetVoid();
26362653
}
26372654

2655+
// Returns the length of an interior vector and a pointer to its first
2656+
// element, in that order.
2657+
fn get_ivec_len_and_data(&@block_ctxt bcx, ValueRef v, ty::t unit_ty) ->
2658+
tup(ValueRef, ValueRef, @block_ctxt) {
2659+
auto llunitty = type_of_or_i8(bcx, unit_ty);
2660+
2661+
auto stack_len = bcx.build.Load(bcx.build.GEP(v,
2662+
[C_int(0), C_uint(abi::ivec_elt_len)]));
2663+
auto stack_elem = bcx.build.GEP(v, [C_int(0),
2664+
C_uint(abi::ivec_elt_elems)]);
2665+
stack_elem = bcx.build.PointerCast(stack_elem, T_ptr(llunitty));
2666+
2667+
auto on_heap = bcx.build.ICmp(lib::llvm::LLVMIntEQ, stack_len, C_int(0));
2668+
2669+
auto on_heap_cx = new_sub_block_ctxt(bcx, "on_heap");
2670+
auto next_cx = new_sub_block_ctxt(bcx, "next");
2671+
bcx.build.CondBr(on_heap, on_heap_cx.llbb, next_cx.llbb);
2672+
2673+
auto heap_stub = on_heap_cx.build.PointerCast(v,
2674+
T_ptr(T_ivec_heap(llunitty)));
2675+
auto heap_ptr = on_heap_cx.build.Load(on_heap_cx.build.GEP(
2676+
heap_stub, [C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)]));
2677+
2678+
// Check whether the heap pointer is null. If it is, the vector length is
2679+
// truly zero.
2680+
auto llstubty = T_ivec_heap(llunitty);
2681+
auto llheapptrty = struct_elt(llstubty, abi::ivec_heap_stub_elt_ptr);
2682+
auto heap_ptr_is_null = on_heap_cx.build.ICmp(lib::llvm::LLVMIntEQ,
2683+
heap_ptr, C_null(T_ptr(llheapptrty)));
2684+
2685+
auto zero_len_cx = new_sub_block_ctxt(bcx, "zero_len");
2686+
auto nonzero_len_cx = new_sub_block_ctxt(bcx, "nonzero_len");
2687+
on_heap_cx.build.CondBr(heap_ptr_is_null, zero_len_cx.llbb,
2688+
nonzero_len_cx.llbb);
2689+
2690+
// Technically this context is unnecessary, but it makes this function
2691+
// clearer.
2692+
auto zero_len = C_int(0);
2693+
auto zero_elem = C_null(T_ptr(llunitty));
2694+
zero_len_cx.build.Br(next_cx.llbb);
2695+
2696+
// If we're here, then we actually have a heapified vector.
2697+
auto heap_len = nonzero_len_cx.build.Load(nonzero_len_cx.build.GEP(
2698+
heap_ptr, [C_int(0), C_uint(abi::ivec_heap_elt_len)]));
2699+
auto heap_elem = nonzero_len_cx.build.GEP(heap_ptr,
2700+
[C_int(0), C_uint(abi::ivec_heap_elt_elems), C_int(0)]);
2701+
nonzero_len_cx.build.Br(next_cx.llbb);
2702+
2703+
// Now we can figure out the length of `v` and get a pointer to its first
2704+
// element.
2705+
auto len = next_cx.build.Phi(T_int(), [stack_len, zero_len, heap_len],
2706+
[bcx.llbb, zero_len_cx.llbb, nonzero_len_cx.llbb]);
2707+
auto elem = next_cx.build.Phi(T_ptr(llunitty),
2708+
[stack_elem, zero_elem, heap_elem],
2709+
[bcx.llbb, zero_len_cx.llbb, nonzero_len_cx.llbb]);
2710+
ret tup(len, elem, next_cx);
2711+
}
2712+
26382713
type val_pair_fn = fn(&@block_ctxt cx, ValueRef dst, ValueRef src) -> result;
26392714

26402715
type val_and_ty_fn = fn(&@block_ctxt cx, ValueRef v, ty::t t) -> result;
@@ -2666,7 +2741,6 @@ fn iter_structural_ty_full(&@block_ctxt cx,
26662741
&ty::t t,
26672742
&val_pair_and_ty_fn f)
26682743
-> result {
2669-
let result r = res(cx, C_nil());
26702744

26712745
fn iter_boxpp(@block_ctxt cx,
26722746
ValueRef box_a_cell,
@@ -2687,6 +2761,45 @@ fn iter_structural_ty_full(&@block_ctxt cx,
26872761
ret res(next_cx, C_nil());
26882762
}
26892763

2764+
fn iter_ivec(@block_ctxt bcx,
2765+
ValueRef av,
2766+
ValueRef bv,
2767+
ty::t unit_ty,
2768+
&val_pair_and_ty_fn f) -> result {
2769+
// FIXME: "unimplemented rebinding existing function" workaround
2770+
fn adapter(&@block_ctxt bcx, ValueRef av, ValueRef bv, ty::t unit_ty,
2771+
val_pair_and_ty_fn f) -> result {
2772+
ret f(bcx, av, bv, unit_ty);
2773+
}
2774+
2775+
auto llunitty = type_of_or_i8(bcx, unit_ty);
2776+
2777+
auto rslt = size_of(bcx, unit_ty);
2778+
auto unit_sz = rslt.val;
2779+
bcx = rslt.bcx;
2780+
2781+
auto a_len_and_data = get_ivec_len_and_data(bcx, av, unit_ty);
2782+
auto a_len = a_len_and_data._0;
2783+
auto a_elem = a_len_and_data._1;
2784+
bcx = a_len_and_data._2;
2785+
2786+
auto b_len_and_data = get_ivec_len_and_data(bcx, bv, unit_ty);
2787+
auto b_len = b_len_and_data._0;
2788+
auto b_elem = b_len_and_data._1;
2789+
bcx = b_len_and_data._2;
2790+
2791+
// Calculate the last pointer address we want to handle.
2792+
auto len = umin(bcx, a_len, b_len);
2793+
auto b_elem_i8 = bcx.build.PointerCast(b_elem, T_ptr(T_i8()));
2794+
auto b_end_i8 = bcx.build.GEP(b_elem_i8, [len]);
2795+
auto b_end = bcx.build.PointerCast(b_end_i8, T_ptr(llunitty));
2796+
2797+
// Now perform the iteration.
2798+
auto vpf = bind adapter(_, _, _, unit_ty, f);
2799+
ret iter_sequence_raw(bcx, a_elem, b_elem, b_end, unit_sz, vpf);
2800+
}
2801+
2802+
let result r = res(cx, C_nil());
26902803
alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
26912804
case (ty::ty_tup(?args)) {
26922805
let int i = 0;
@@ -2831,6 +2944,13 @@ fn iter_structural_ty_full(&@block_ctxt cx,
28312944
C_int(abi::obj_field_box)]);
28322945
ret iter_boxpp(cx, box_cell_a, box_cell_b, f);
28332946
}
2947+
case (ty::ty_ivec(?unit_tm)) {
2948+
ret iter_ivec(cx, av, bv, unit_tm.ty, f);
2949+
}
2950+
case (ty::ty_istr) {
2951+
auto unit_ty = ty::mk_mach(cx.fcx.lcx.ccx.tcx, common::ty_u8);
2952+
ret iter_ivec(cx, av, bv, unit_ty, f);
2953+
}
28342954
case (_) {
28352955
cx.fcx.lcx.ccx.sess.unimpl("type in iter_structural_ty_full");
28362956
}
@@ -5475,6 +5595,93 @@ fn trans_vec(&@block_ctxt cx, &vec[@ast::expr] args,
54755595
ret res(bcx, vec_val);
54765596
}
54775597

5598+
fn trans_ivec(@block_ctxt bcx, &vec[@ast::expr] args, &ast::ann ann)
5599+
-> result {
5600+
auto typ = node_ann_type(bcx.fcx.lcx.ccx, ann);
5601+
auto unit_ty;
5602+
alt (ty::struct(bcx.fcx.lcx.ccx.tcx, typ)) {
5603+
case (ty::ty_ivec(?mt)) { unit_ty = mt.ty; }
5604+
case (_) { bcx.fcx.lcx.ccx.sess.bug("non-ivec type in trans_ivec"); }
5605+
}
5606+
5607+
auto rslt = size_of(bcx, unit_ty);
5608+
auto unit_sz = rslt.val;
5609+
bcx = rslt.bcx;
5610+
rslt = align_of(bcx, unit_ty);
5611+
auto unit_align = rslt.val;
5612+
bcx = rslt.bcx;
5613+
5614+
auto llunitty = type_of_or_i8(bcx, unit_ty);
5615+
auto llvecptr = alloca(bcx, T_ivec());
5616+
auto lllen = bcx.build.Mul(C_uint(vec::len(args)), unit_sz);
5617+
5618+
// Allocate the vector pieces and store length and allocated length.
5619+
auto llfirsteltptr;
5620+
if (vec::len(args) > 0u && vec::len(args) < abi::ivec_default_size) {
5621+
// Interior case.
5622+
bcx.build.Store(lllen, bcx.build.GEP(llvecptr,
5623+
[C_int(0), C_uint(abi::ivec_elt_len)]));
5624+
bcx.build.Store(C_uint(abi::ivec_elt_alen), bcx.build.GEP(llvecptr,
5625+
[C_int(0), C_uint(abi::ivec_elt_alen)]));
5626+
llfirsteltptr = bcx.build.GEP(llvecptr,
5627+
[C_int(0), C_uint(abi::ivec_elt_elems)]);
5628+
} else {
5629+
// Heap case.
5630+
auto llstubty = T_ivec_heap(llunitty);
5631+
auto llstubptr = bcx.build.PointerCast(llvecptr, T_ptr(llstubty));
5632+
5633+
bcx.build.Store(C_int(0), bcx.build.GEP(llstubptr,
5634+
[C_int(0), C_uint(abi::ivec_heap_stub_elt_zero)]));
5635+
bcx.build.Store(C_uint(abi::ivec_elt_alen), bcx.build.GEP(llstubptr,
5636+
[C_int(0), C_uint(abi::ivec_heap_stub_elt_alen)]));
5637+
5638+
auto llheapty = struct_elt(llstubty, abi::ivec_heap_stub_elt_ptr);
5639+
5640+
if (vec::len(args) == 0u) {
5641+
// Null heap pointer indicates a zero-length vector.
5642+
bcx.build.Store(C_null(T_ptr(llheapty)), bcx.build.GEP(llstubptr,
5643+
[C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)]));
5644+
llfirsteltptr = C_null(T_ptr(llunitty));
5645+
} else {
5646+
auto llheapsz = bcx.build.Add(llsize_of(llheapty), lllen);
5647+
rslt = trans_raw_malloc(bcx, llheapty, llheapsz);
5648+
bcx = rslt.bcx;
5649+
auto llheapptr = rslt.val;
5650+
5651+
bcx.build.Store(llheapptr, bcx.build.GEP(llstubptr,
5652+
[C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)]));
5653+
bcx.build.Store(lllen, bcx.build.GEP(llheapptr,
5654+
[C_int(0), C_uint(abi::ivec_heap_elt_len)]));
5655+
llfirsteltptr = bcx.build.GEP(llheapptr,
5656+
[C_int(0), C_uint(abi::ivec_heap_elt_elems)]);
5657+
}
5658+
}
5659+
5660+
llfirsteltptr = bcx.build.PointerCast(llfirsteltptr, T_ptr(llunitty));
5661+
5662+
// Store the individual elements.
5663+
auto i = 0u;
5664+
for (@ast::expr e in args) {
5665+
rslt = trans_expr(bcx, e);
5666+
bcx = rslt.bcx;
5667+
auto llsrc = rslt.val;
5668+
5669+
auto lleltptr;
5670+
if (ty::type_has_dynamic_size(bcx.fcx.lcx.ccx.tcx, unit_ty)) {
5671+
lleltptr = bcx.build.GEP(llfirsteltptr,
5672+
[bcx.build.Mul(C_uint(i), unit_align)]);
5673+
} else {
5674+
lleltptr = bcx.build.GEP(llfirsteltptr, [C_uint(i)]);
5675+
}
5676+
5677+
bcx = copy_val(bcx, INIT, lleltptr, llsrc, unit_ty).bcx;
5678+
5679+
i += 1u;
5680+
}
5681+
5682+
ret res(bcx, llvecptr);
5683+
}
5684+
54785685
fn trans_rec(&@block_ctxt cx, &vec[ast::field] fields,
54795686
&option::t[@ast::expr] base, &ast::ann ann) -> result {
54805687

@@ -5649,10 +5856,14 @@ fn trans_expr_out(&@block_ctxt cx, &@ast::expr e, out_method output)
56495856
ret trans_cast(cx, e, ann);
56505857
}
56515858

5652-
case (ast::expr_vec(?args, _, _, ?ann)) {
5859+
case (ast::expr_vec(?args, _, ast::sk_rc, ?ann)) {
56535860
ret trans_vec(cx, args, ann);
56545861
}
56555862

5863+
case (ast::expr_vec(?args, _, ast::sk_unique, ?ann)) {
5864+
ret trans_ivec(cx, args, ann);
5865+
}
5866+
56565867
case (ast::expr_tup(?args, ?ann)) {
56575868
ret trans_tup(cx, args, ann);
56585869
}

src/comp/middle/ty.rs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -742,31 +742,37 @@ fn type_is_bool(&ctxt cx, &t ty) -> bool {
742742

743743
fn type_is_structural(&ctxt cx, &t ty) -> bool {
744744
alt (struct(cx, ty)) {
745-
case (ty_tup(_)) { ret true; }
746-
case (ty_rec(_)) { ret true; }
747-
case (ty_tag(_,_)) { ret true; }
745+
case (ty_tup(_)) { ret true; }
746+
case (ty_rec(_)) { ret true; }
747+
case (ty_tag(_,_)) { ret true; }
748748
case (ty_fn(_,_,_,_,_)) { ret true; }
749-
case (ty_obj(_)) { ret true; }
750-
case (_) { ret false; }
749+
case (ty_obj(_)) { ret true; }
750+
case (ty_ivec(_)) { ret true; }
751+
case (ty_istr) { ret true; }
752+
case (_) { ret false; }
751753
}
752754
}
753755

754756
fn type_is_sequence(&ctxt cx, &t ty) -> bool {
755757
alt (struct(cx, ty)) {
756-
case (ty_str) { ret true; }
758+
case (ty_str) { ret true; }
759+
case (ty_istr) { ret true; }
757760
case (ty_vec(_)) { ret true; }
761+
case (ty_ivec(_)) { ret true; }
758762
case (_) { ret false; }
759763
}
760764
}
761765

762766
fn sequence_element_type(&ctxt cx, &t ty) -> t {
763767
alt (struct(cx, ty)) {
764-
case (ty_str) { ret mk_mach(cx, common::ty_u8); }
765-
case (ty_vec(?mt)) { ret mt.ty; }
766-
// NB: This is not exhaustive.
768+
case (ty_str) { ret mk_mach(cx, common::ty_u8); }
769+
case (ty_istr) { ret mk_mach(cx, common::ty_u8); }
770+
case (ty_vec(?mt)) { ret mt.ty; }
771+
case (ty_ivec(?mt)) { ret mt.ty; }
772+
case (_) {
773+
cx.sess.bug("sequence_element_type called on non-sequence value");
774+
}
767775
}
768-
769-
cx.sess.bug("sequence_element_type called on non-sequence value");
770776
}
771777

772778
fn type_is_tup_like(&ctxt cx, &t ty) -> bool {

0 commit comments

Comments
 (0)