@@ -584,20 +584,29 @@ fn T_opaque_ivec() -> TypeRef {
584
584
T_array ( T_i8 ( ) , abi:: ivec_default_size) ] ) ; // Body elements
585
585
}
586
586
587
- // Interior vector on the heap. Cast to this when the allocated length (second
588
- // element of T_ivec above) is zero.
587
+ fn T_ivec_heap_part ( TypeRef t) -> TypeRef {
588
+ ret T_struct ( [ T_int ( ) , // Real length
589
+ T_array ( t, 0 u) ] ) ; // Body elements
590
+ }
591
+
592
+ // Interior vector on the heap, also known as the "stub". Cast to this when
593
+ // the allocated length (second element of T_ivec above) is zero.
589
594
fn T_ivec_heap ( TypeRef t) -> TypeRef {
590
- ret T_struct ( [ T_int ( ) , // Length (zero)
591
- T_int ( ) , // Alloc
592
- T_ptr ( T_struct ( [ T_int ( ) , // Real length
593
- T_array ( t, 0 u) ] ) ) ] ) ; // Body elements
595
+ ret T_struct ( [ T_int ( ) , // Length (zero)
596
+ T_int ( ) , // Alloc
597
+ T_ptr ( T_ivec_heap_part ( t) ) ] ) ; // Pointer
598
+ }
599
+
600
+ fn T_opaque_ivec_heap_part ( ) -> TypeRef {
601
+ ret T_struct ( [ T_int ( ) , // Real length
602
+ T_array ( T_i8 ( ) , 0 u) ] ) ; // Body elements
603
+
594
604
}
595
605
596
606
fn T_opaque_ivec_heap ( ) -> TypeRef {
597
- ret T_struct ( [ T_int ( ) , // Length (zero)
598
- T_int ( ) , // Alloc
599
- T_ptr ( T_struct ( [ T_int ( ) , // Real length
600
- T_array ( T_i8 ( ) , 0 u) ] ) ) ] ) ; // Body elements
607
+ ret T_struct ( [ T_int ( ) , // Length (zero)
608
+ T_int ( ) , // Alloc
609
+ T_ptr ( T_opaque_ivec_heap_part ( ) ) ] ) ; // Pointer
601
610
}
602
611
603
612
fn T_str ( ) -> TypeRef {
@@ -2670,9 +2679,8 @@ fn get_ivec_len_and_data(&@block_ctxt bcx, ValueRef v, ty::t unit_ty) ->
2670
2679
2671
2680
auto stack_len = bcx. build . Load ( bcx. build . InBoundsGEP ( v,
2672
2681
[ C_int ( 0 ) , C_uint ( abi:: ivec_elt_len) ] ) ) ;
2673
- auto stack_elem = bcx. build . InBoundsGEP ( v, [ C_int ( 0 ) ,
2674
- C_uint ( abi:: ivec_elt_elems) ,
2675
- C_int ( 0 ) ] ) ;
2682
+ auto stack_elem = bcx. build . InBoundsGEP ( v,
2683
+ [ C_int ( 0 ) , C_uint ( abi:: ivec_elt_elems) , C_int ( 0 ) ] ) ;
2676
2684
2677
2685
auto on_heap = bcx. build . ICmp ( lib:: llvm:: LLVMIntEQ , stack_len, C_int ( 0 ) ) ;
2678
2686
@@ -3680,6 +3688,201 @@ fn trans_vec_append(&@block_ctxt cx, &ty::t t,
3680
3688
dst, src, skip_null] ) ) ;
3681
3689
}
3682
3690
3691
+ // Returns a tuple consisting of a pointer to the length (to be updated), a
3692
+ // pointer to the newly-reserved space, and a block context.
3693
+ fn reserve_ivec_space( & @block_ctxt cx, TypeRef llunitty, ValueRef v,
3694
+ ValueRef len_needed) -> tup( ValueRef , ValueRef , @block_ctxt) {
3695
+ auto stack_len_ptr = cx. build. InBoundsGEP ( v, [ C_int ( 0 ) ,
3696
+ C_uint ( abi:: ivec_elt_len) ] ) ;
3697
+ auto stack_len = cx. build. Load ( stack_len_ptr) ;
3698
+ auto alen = cx. build. Load ( cx. build. InBoundsGEP ( v,
3699
+ [ C_int ( 0 ) , C_uint ( abi:: ivec_elt_alen) ] ) ) ;
3700
+
3701
+ // There are four cases we have to consider:
3702
+ // (1) On heap, no resize necessary.
3703
+ // (2) On heap, need to resize.
3704
+ // (3) On stack, no resize necessary.
3705
+ // (4) On stack, need to spill to heap.
3706
+
3707
+ auto maybe_on_heap = cx. build. ICmp ( lib:: llvm:: LLVMIntEQ , stack_len,
3708
+ C_int ( 0 ) ) ;
3709
+ auto maybe_on_heap_cx = new_sub_block_ctxt( cx, "maybe_on_heap") ;
3710
+ auto on_stack_cx = new_sub_block_ctxt( cx, "on_stack") ;
3711
+ cx. build. CondBr ( maybe_on_heap, maybe_on_heap_cx. llbb, on_stack_cx. llbb) ;
3712
+
3713
+ auto next_cx = new_sub_block_ctxt( cx, "next") ;
3714
+
3715
+ // We're possibly on the heap, unless the vector is zero-length.
3716
+ auto stub_ptr = maybe_on_heap_cx. build. PointerCast ( v,
3717
+ T_ptr ( T_ivec_heap ( llunitty) ) ) ;
3718
+ auto heap_ptr = maybe_on_heap_cx. build. Load (
3719
+ maybe_on_heap_cx. build. InBoundsGEP ( stub_ptr,
3720
+ [ C_int ( 0 ) , C_uint ( abi:: ivec_heap_stub_elt_ptr) ] ) ) ;
3721
+ auto on_heap = maybe_on_heap_cx. build. ICmp ( lib:: llvm:: LLVMIntNE , heap_ptr,
3722
+ C_null ( val_ty( heap_ptr) ) ) ;
3723
+ auto on_heap_cx = new_sub_block_ctxt( cx, "on_heap") ;
3724
+ maybe_on_heap_cx. build. CondBr ( on_heap, on_heap_cx. llbb, on_stack_cx. llbb) ;
3725
+
3726
+ // We're definitely on the heap. Check whether we need to resize.
3727
+ auto heap_len_ptr = on_heap_cx. build. InBoundsGEP ( heap_ptr, [ C_int ( 0 ) ,
3728
+ C_int ( 0 ) ] ) ;
3729
+ auto heap_len = on_heap_cx. build. Load ( heap_len_ptr) ;
3730
+ auto new_heap_len = on_heap_cx. build. Add ( heap_len, len_needed) ;
3731
+ auto heap_no_resize_needed = on_heap_cx. build. ICmp ( lib:: llvm:: LLVMIntULT ,
3732
+ new_heap_len, alen) ;
3733
+ auto heap_no_resize_cx = new_sub_block_ctxt( cx, "heap_no_resize") ;
3734
+ auto heap_resize_cx = new_sub_block_ctxt( cx, "heap_resize") ;
3735
+ on_heap_cx. build. CondBr ( heap_no_resize_needed, heap_no_resize_cx. llbb,
3736
+ heap_resize_cx. llbb) ;
3737
+
3738
+ // Case (1): We're on the heap and don't need to resize.
3739
+ auto heap_len_unscaled = heap_no_resize_cx. build. UDiv ( heap_len,
3740
+ llsize_of( llunitty) ) ;
3741
+ auto heap_data_no_resize = heap_no_resize_cx. build. InBoundsGEP ( heap_ptr,
3742
+ [ C_int ( 0 ) , C_uint ( abi:: ivec_heap_elt_elems) , heap_len_unscaled] ) ;
3743
+ heap_no_resize_cx. build. Br ( next_cx. llbb) ;
3744
+
3745
+ // Case (2): We're on the heap and need to resize. This path is rare, so
3746
+ // we delegate to cold glue.
3747
+ heap_resize_cx. build. Call (
3748
+ cx. fcx. lcx. ccx. upcalls. ivec_resize, [
3749
+ cx. fcx. lltaskptr,
3750
+ heap_resize_cx. build. PointerCast ( v, T_ptr ( T_opaque_ivec ( ) ) ) ,
3751
+ new_heap_len
3752
+ ] ) ;
3753
+ auto heap_ptr_resize = heap_resize_cx. build. Load (
3754
+ heap_resize_cx. build. InBoundsGEP ( stub_ptr,
3755
+ [ C_int ( 0 ) , C_uint ( abi:: ivec_heap_stub_elt_ptr) ] ) ) ;
3756
+ auto heap_data_resize = heap_resize_cx. build. InBoundsGEP ( heap_ptr_resize,
3757
+ [ C_int ( 0 ) , C_uint ( abi:: ivec_heap_elt_elems) , C_int ( 0 ) ] ) ;
3758
+ heap_resize_cx. build. Br ( next_cx. llbb) ;
3759
+
3760
+ // We're on the stack. Check whether we need to spill to the heap.
3761
+ auto new_stack_len = on_stack_cx. build. Add ( stack_len, len_needed) ;
3762
+ auto stack_no_spill_needed = on_stack_cx. build. ICmp ( lib:: llvm:: LLVMIntULT ,
3763
+ new_stack_len, alen) ;
3764
+ auto stack_no_spill_cx = new_sub_block_ctxt( cx, "stack_no_spill") ;
3765
+ auto stack_spill_cx = new_sub_block_ctxt( cx, "stack_spill") ;
3766
+ on_stack_cx. build. CondBr ( stack_no_spill_needed, stack_no_spill_cx. llbb,
3767
+ stack_spill_cx. llbb) ;
3768
+
3769
+ // Case (3): We're on the stack and don't need to spill.
3770
+ auto stack_len_unscaled = stack_no_spill_cx. build. UDiv ( stack_len,
3771
+ llsize_of( llunitty) ) ;
3772
+ auto stack_data_no_spill = stack_no_spill_cx. build. InBoundsGEP ( v,
3773
+ [ C_int ( 0 ) , C_uint ( abi:: ivec_elt_elems) , stack_len_unscaled] ) ;
3774
+ stack_no_spill_cx. build. Br ( next_cx. llbb) ;
3775
+
3776
+ // Case (4): We're on the stack and need to spill. Like case (2), this
3777
+ // path is rare, so we delegate to cold glue.
3778
+ stack_spill_cx. build. Call (
3779
+ cx. fcx. lcx. ccx. upcalls. ivec_spill, [
3780
+ cx. fcx. lltaskptr,
3781
+ stack_spill_cx. build. PointerCast ( v, T_ptr ( T_opaque_ivec ( ) ) ) ,
3782
+ new_stack_len
3783
+ ] ) ;
3784
+ auto spill_stub = stack_spill_cx. build. PointerCast ( v,
3785
+ T_ptr ( T_ivec_heap ( llunitty) ) ) ;
3786
+ auto heap_ptr_spill = stack_spill_cx. build. Load (
3787
+ stack_spill_cx. build. InBoundsGEP ( spill_stub,
3788
+ [ C_int ( 0 ) , C_uint ( abi:: ivec_heap_stub_elt_ptr) ] ) ) ;
3789
+ auto heap_len_ptr_spill = stack_spill_cx. build. InBoundsGEP ( heap_ptr_spill,
3790
+ [ C_int ( 0 ) , C_uint ( abi:: ivec_heap_elt_len) ] ) ;
3791
+ auto heap_data_spill = stack_spill_cx. build. InBoundsGEP ( heap_ptr_spill,
3792
+ [ C_int ( 0 ) , C_uint ( abi:: ivec_heap_elt_elems) , C_int ( 0 ) ] ) ;
3793
+
3794
+ stack_spill_cx. build. Br ( next_cx. llbb) ;
3795
+
3796
+ // Phi together the different data pointers to get the result.
3797
+ auto len_ptr = next_cx. build. Phi ( T_ptr ( T_int ( ) ) ,
3798
+ [ heap_len_ptr, heap_len_ptr, stack_len_ptr, heap_len_ptr_spill] ,
3799
+ [ heap_no_resize_cx. llbb, heap_resize_cx. llbb, stack_no_spill_cx. llbb,
3800
+ stack_spill_cx. llbb] ) ;
3801
+ auto data_ptr = next_cx. build. Phi ( T_ptr ( llunitty) ,
3802
+ [ heap_data_no_resize, heap_data_resize, stack_data_no_spill,
3803
+ heap_data_spill] ,
3804
+ [ heap_no_resize_cx. llbb, heap_resize_cx. llbb, stack_no_spill_cx. llbb,
3805
+ stack_spill_cx. llbb] ) ;
3806
+ ret tup( len_ptr, data_ptr, next_cx) ;
3807
+ }
3808
+
3809
+ fn trans_ivec_append( & @block_ctxt cx, & ty:: t t, ValueRef lhs, ValueRef rhs)
3810
+ -> result {
3811
+ auto unit_ty = ty:: sequence_element_type( cx. fcx. lcx. ccx. tcx, t) ;
3812
+ auto llunitty = type_of_or_i8( cx, unit_ty) ;
3813
+
3814
+ auto skip_null;
3815
+ alt ( ty:: struct ( cx. fcx. lcx. ccx. tcx, t) ) {
3816
+ case ( ty:: ty_istr) { skip_null = true; }
3817
+ case ( ty:: ty_ivec( _) ) { skip_null = false; }
3818
+ case ( _) {
3819
+ cx. fcx. lcx. ccx. tcx. sess. bug( "non-istr/ivec in trans_ivec_append") ;
3820
+ }
3821
+ }
3822
+
3823
+ // Gather the various type descriptors we'll need.
3824
+ auto rslt = get_tydesc( cx, t, false, none) ;
3825
+ auto vec_tydesc = rslt. val;
3826
+ auto bcx = rslt. bcx;
3827
+
3828
+ rslt = get_tydesc( bcx, unit_ty, false, none) ;
3829
+ auto unit_tydesc = rslt. val;
3830
+ bcx = rslt. bcx;
3831
+ lazily_emit_tydesc_glue( bcx, abi:: tydesc_field_take_glue, none) ;
3832
+ lazily_emit_tydesc_glue( bcx, abi:: tydesc_field_drop_glue, none) ;
3833
+ lazily_emit_tydesc_glue( bcx, abi:: tydesc_field_free_glue, none) ;
3834
+
3835
+ auto rhs_len_and_data = get_ivec_len_and_data( bcx, rhs, unit_ty) ;
3836
+ auto rhs_len = rhs_len_and_data. _0;
3837
+ auto rhs_data = rhs_len_and_data. _1;
3838
+ bcx = rhs_len_and_data. _2;
3839
+
3840
+ auto lhs_len_ptr_and_data =
3841
+ reserve_ivec_space( bcx, llunitty, lhs, rhs_len) ;
3842
+ auto lhs_len_ptr = lhs_len_ptr_and_data. _0;
3843
+ auto lhs_data = lhs_len_ptr_and_data. _1;
3844
+ bcx = lhs_len_ptr_and_data. _2;
3845
+
3846
+ // Work out the end pointer.
3847
+ auto lhs_unscaled_idx = bcx. build. UDiv ( rhs_len, llsize_of( llunitty) ) ;
3848
+ auto lhs_end = bcx. build. InBoundsGEP ( lhs_data, [ lhs_unscaled_idx] ) ;
3849
+
3850
+ // Now emit the copy loop.
3851
+ auto dest_ptr = alloca( bcx, T_ptr ( llunitty) ) ;
3852
+ bcx. build. Store ( lhs_data, dest_ptr) ;
3853
+ auto src_ptr = alloca( bcx, T_ptr ( llunitty) ) ;
3854
+ bcx. build. Store ( rhs_data, src_ptr) ;
3855
+
3856
+ auto copy_loop_header_cx = new_sub_block_ctxt( bcx, "copy_loop_header") ;
3857
+ bcx. build. Br ( copy_loop_header_cx. llbb) ;
3858
+
3859
+ auto copy_dest_ptr = copy_loop_header_cx. build. Load ( dest_ptr) ;
3860
+ auto not_yet_at_end = copy_loop_header_cx. build. ICmp ( lib:: llvm:: LLVMIntNE ,
3861
+ copy_dest_ptr, lhs_end) ;
3862
+ auto copy_loop_body_cx = new_sub_block_ctxt( bcx, "copy_loop_body") ;
3863
+ auto next_cx = new_sub_block_ctxt( bcx, "next") ;
3864
+ copy_loop_header_cx. build. CondBr ( not_yet_at_end, copy_loop_body_cx. llbb,
3865
+ next_cx. llbb) ;
3866
+
3867
+ auto copy_src_ptr = copy_loop_body_cx. build. Load ( src_ptr) ;
3868
+ rslt = copy_val( copy_loop_body_cx, INIT , copy_dest_ptr, copy_src_ptr, t) ;
3869
+ auto post_copy_cx = rslt. bcx;
3870
+
3871
+ // Increment both pointers.
3872
+ post_copy_cx. build. Store ( post_copy_cx. build. InBoundsGEP ( copy_dest_ptr,
3873
+ [ C_int ( 1 ) ] ) , dest_ptr) ;
3874
+ post_copy_cx. build. Store ( post_copy_cx. build. InBoundsGEP ( copy_src_ptr,
3875
+ [ C_int ( 1 ) ] ) , src_ptr) ;
3876
+ post_copy_cx. build. Br ( copy_loop_header_cx. llbb) ;
3877
+
3878
+ // Write in the new length.
3879
+ auto new_len = next_cx. build. Add ( next_cx. build. Load ( lhs_len_ptr) ,
3880
+ rhs_len) ;
3881
+ next_cx. build. Store ( new_len, lhs_len_ptr) ;
3882
+
3883
+ ret res( next_cx, C_nil ( ) ) ;
3884
+ }
3885
+
3683
3886
fn trans_vec_add( & @block_ctxt cx, & ty:: t t,
3684
3887
ValueRef lhs, ValueRef rhs) -> result {
3685
3888
auto r = alloc_ty( cx, t) ;
@@ -4741,14 +4944,8 @@ fn trans_index(&@block_ctxt cx, &span sp, &@ast::expr base,
4741
4944
auto base_ty = ty:: expr_ty( cx. fcx. lcx. ccx. tcx, base) ;
4742
4945
auto base_ty_no_boxes = ty:: strip_boxes( cx. fcx. lcx. ccx. tcx, base_ty) ;
4743
4946
4744
- auto is_interior;
4745
- alt ( ty:: struct( cx. fcx. lcx. ccx. tcx, base_ty_no_boxes) ) {
4746
- // TODO: Or-patterns
4747
- case ( ty:: ty_vec( _) ) { is_interior = false; }
4748
- case ( ty:: ty_str) { is_interior = false ; }
4749
- case ( ty:: ty_ivec( _) ) { is_interior = true ; }
4750
- case ( ty:: ty_istr) { is_interior = true ; }
4751
- } ;
4947
+ auto is_interior = ty:: sequence_is_interior( cx. fcx. lcx. ccx. tcx,
4948
+ base_ty_no_boxes) ;
4752
4949
4753
4950
auto lv = trans_expr( cx, base) ;
4754
4951
lv = autoderef( lv. bcx, lv. val, base_ty) ;
@@ -5655,40 +5852,43 @@ fn trans_ivec(@block_ctxt bcx, &vec[@ast::expr] args, &ast::ann ann)
5655
5852
auto llfirsteltptr;
5656
5853
if ( vec:: len( args) > 0 u && vec:: len( args) < abi:: ivec_default_size) {
5657
5854
// Interior case.
5658
- bcx. build. Store ( lllen, bcx. build. GEP ( llvecptr,
5855
+ bcx. build. Store ( lllen, bcx. build. InBoundsGEP ( llvecptr,
5659
5856
[ C_int( 0 ) , C_uint ( abi : : ivec_elt_len) ] ) ) ;
5660
- bcx. build. Store ( C_uint ( abi:: ivec_elt_alen) , bcx. build. GEP ( llvecptr,
5661
- [ C_int ( 0 ) , C_uint ( abi:: ivec_elt_alen) ] ) ) ;
5662
- llfirsteltptr = bcx. build. GEP ( llvecptr,
5857
+ bcx. build. Store ( C_uint ( abi:: ivec_default_size) ,
5858
+ bcx. build. InBoundsGEP ( llvecptr,
5859
+ [ C_int ( 0 ) , C_uint ( abi:: ivec_elt_alen) ] ) ) ;
5860
+ llfirsteltptr = bcx. build. InBoundsGEP ( llvecptr,
5663
5861
[ C_int ( 0 ) , C_uint ( abi:: ivec_elt_elems) , C_int ( 0 ) ] ) ;
5664
5862
} else {
5665
5863
// Heap case.
5666
5864
auto llstubty = T_ivec_heap ( llunitty) ;
5667
5865
auto llstubptr = bcx. build. PointerCast ( llvecptr, T_ptr ( llstubty) ) ;
5668
5866
5669
- bcx. build. Store ( C_int ( 0 ) , bcx. build. GEP ( llstubptr,
5867
+ bcx. build. Store ( C_int ( 0 ) , bcx. build. InBoundsGEP ( llstubptr,
5670
5868
[ C_int ( 0 ) , C_uint ( abi:: ivec_heap_stub_elt_zero) ] ) ) ;
5671
- bcx. build. Store ( C_uint ( abi:: ivec_elt_alen) , bcx. build. GEP ( llstubptr,
5672
- [ C_int ( 0 ) , C_uint ( abi:: ivec_heap_stub_elt_alen) ] ) ) ;
5869
+ bcx. build. Store ( lllen,
5870
+ bcx. build. InBoundsGEP ( llstubptr,
5871
+ [ C_int ( 0 ) , C_uint ( abi:: ivec_heap_stub_elt_alen) ] ) ) ;
5673
5872
5674
5873
auto llheapty = struct_elt( llstubty, abi:: ivec_heap_stub_elt_ptr) ;
5675
5874
5676
5875
if ( vec:: len( args) == 0 u) {
5677
5876
// Null heap pointer indicates a zero-length vector.
5678
- bcx. build. Store ( C_null ( T_ptr ( llheapty) ) , bcx. build. GEP ( llstubptr,
5679
- [ C_int ( 0 ) , C_uint ( abi:: ivec_heap_stub_elt_ptr) ] ) ) ;
5877
+ bcx. build. Store ( C_null ( T_ptr ( llheapty) ) ,
5878
+ bcx. build. InBoundsGEP ( llstubptr,
5879
+ [ C_int ( 0 ) , C_uint ( abi:: ivec_heap_stub_elt_ptr) ] ) ) ;
5680
5880
llfirsteltptr = C_null ( T_ptr ( llunitty) ) ;
5681
5881
} else {
5682
5882
auto llheapsz = bcx. build. Add ( llsize_of( llheapty) , lllen) ;
5683
5883
rslt = trans_raw_malloc( bcx, llheapty, llheapsz) ;
5684
5884
bcx = rslt. bcx;
5685
5885
auto llheapptr = rslt. val;
5686
5886
5687
- bcx. build. Store ( llheapptr, bcx. build. GEP ( llstubptr,
5887
+ bcx. build. Store ( llheapptr, bcx. build. InBoundsGEP ( llstubptr,
5688
5888
[ C_int ( 0 ) , C_uint ( abi:: ivec_heap_stub_elt_ptr) ] ) ) ;
5689
- bcx. build. Store ( lllen, bcx. build. GEP ( llheapptr,
5889
+ bcx. build. Store ( lllen, bcx. build. InBoundsGEP ( llheapptr,
5690
5890
[ C_int ( 0 ) , C_uint ( abi:: ivec_heap_elt_len) ] ) ) ;
5691
- llfirsteltptr = bcx. build. GEP ( llheapptr,
5891
+ llfirsteltptr = bcx. build. InBoundsGEP ( llheapptr,
5692
5892
[ C_int ( 0 ) , C_uint ( abi:: ivec_heap_elt_elems) , C_int ( 0 ) ] ) ;
5693
5893
}
5694
5894
}
@@ -5864,6 +6064,11 @@ fn trans_expr_out(&@block_ctxt cx, &@ast::expr e, out_method output)
5864
6064
if ( ty:: type_is_sequence( cx. fcx. lcx. ccx. tcx, t) ) {
5865
6065
alt ( op) {
5866
6066
case ( ast:: add) {
6067
+ if ( ty:: sequence_is_interior( cx. fcx. lcx. ccx. tcx, t) ) {
6068
+ ret trans_ivec_append( rhs_res. bcx, t,
6069
+ lhs_res. res. val,
6070
+ rhs_res. val) ;
6071
+ }
5867
6072
ret trans_vec_append( rhs_res. bcx, t,
5868
6073
lhs_res. res. val,
5869
6074
rhs_res. val) ;
0 commit comments