]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/tvec.rs
30a7648e7eafb26f79b1c4e74a61d4cf5e6362bd
[rust.git] / src / librustc / middle / trans / tvec.rs
1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11
12 use back::abi;
13 use lib;
14 use lib::llvm::{llvm, ValueRef, TypeRef};
15 use middle::trans::base;
16 use middle::trans::base::*;
17 use middle::trans::build::*;
18 use middle::trans::callee;
19 use middle::trans::common::*;
20 use middle::trans::datum::*;
21 use middle::trans::expr::{Dest, Ignore, SaveIn};
22 use middle::trans::expr;
23 use middle::trans::glue;
24 use middle::trans::machine::{llsize_of, nonzero_llsize_of};
25 use middle::trans::type_of;
26 use middle::ty;
27 use util::common::indenter;
28 use util::ppaux::ty_to_str;
29
30 use core::option::None;
31 use core::vec;
32 use syntax::ast;
33 use syntax::codemap;
34
35 // Boxed vector types are in some sense currently a "shorthand" for a box
36 // containing an unboxed vector. This expands a boxed vector type into such an
37 // expanded type. It doesn't respect mutability, but that doesn't matter at
38 // this point.
39 pub fn expand_boxed_vec_ty(tcx: ty::ctxt, t: ty::t) -> ty::t {
40     let unit_ty = ty::sequence_element_type(tcx, t);
41     let unboxed_vec_ty = ty::mk_mut_unboxed_vec(tcx, unit_ty);
42     match ty::get(t).sty {
43       ty::ty_estr(ty::vstore_uniq) | ty::ty_evec(_, ty::vstore_uniq) => {
44         ty::mk_imm_uniq(tcx, unboxed_vec_ty)
45       }
46       ty::ty_estr(ty::vstore_box) | ty::ty_evec(_, ty::vstore_box) => {
47         ty::mk_imm_box(tcx, unboxed_vec_ty)
48       }
49       _ => tcx.sess.bug(~"non boxed-vec type \
50                           in tvec::expand_boxed_vec_ty")
51     }
52 }
53
54 pub fn get_fill(bcx: block, vptr: ValueRef) -> ValueRef {
55     let _icx = bcx.insn_ctxt("tvec::get_fill");
56     Load(bcx, GEPi(bcx, vptr, [0u, abi::vec_elt_fill]))
57 }
58 pub fn set_fill(bcx: block, vptr: ValueRef, fill: ValueRef) {
59     Store(bcx, fill, GEPi(bcx, vptr, [0u, abi::vec_elt_fill]));
60 }
61 pub fn get_alloc(bcx: block, vptr: ValueRef) -> ValueRef {
62     Load(bcx, GEPi(bcx, vptr, [0u, abi::vec_elt_alloc]))
63 }
64
65 pub fn get_bodyptr(bcx: block, vptr: ValueRef) -> ValueRef {
66     base::non_gc_box_cast(bcx, GEPi(bcx, vptr, [0u, abi::box_field_body]))
67 }
68
69 pub fn get_dataptr(bcx: block, vptr: ValueRef) -> ValueRef {
70     let _icx = bcx.insn_ctxt("tvec::get_dataptr");
71     GEPi(bcx, vptr, [0u, abi::vec_elt_elems, 0u])
72 }
73
74 pub fn pointer_add(bcx: block, ptr: ValueRef, bytes: ValueRef) -> ValueRef {
75     let _icx = bcx.insn_ctxt("tvec::pointer_add");
76     let old_ty = val_ty(ptr);
77     let bptr = PointerCast(bcx, ptr, T_ptr(T_i8()));
78     return PointerCast(bcx, InBoundsGEP(bcx, bptr, ~[bytes]), old_ty);
79 }
80
81 pub fn alloc_raw(bcx: block, unit_ty: ty::t,
82                  fill: ValueRef, alloc: ValueRef, heap: heap) -> Result {
83     let _icx = bcx.insn_ctxt("tvec::alloc_uniq");
84     let ccx = bcx.ccx();
85
86     let vecbodyty = ty::mk_mut_unboxed_vec(bcx.tcx(), unit_ty);
87     let vecsize = Add(bcx, alloc, llsize_of(ccx, ccx.opaque_vec_type));
88
89     let base::MallocResult {bcx, box: bx, body} =
90         base::malloc_general_dyn(bcx, vecbodyty, heap, vecsize);
91     Store(bcx, fill, GEPi(bcx, body, [0u, abi::vec_elt_fill]));
92     Store(bcx, alloc, GEPi(bcx, body, [0u, abi::vec_elt_alloc]));
93     base::maybe_set_managed_unique_rc(bcx, bx, heap);
94     return rslt(bcx, bx);
95 }
96
97 pub fn alloc_uniq_raw(bcx: block, unit_ty: ty::t,
98                       fill: ValueRef, alloc: ValueRef) -> Result {
99     alloc_raw(bcx, unit_ty, fill, alloc, base::heap_for_unique(bcx, unit_ty))
100 }
101
102 pub fn alloc_vec(bcx: block,
103                  unit_ty: ty::t,
104                  elts: uint,
105                  heap: heap)
106               -> Result {
107     let _icx = bcx.insn_ctxt("tvec::alloc_uniq");
108     let ccx = bcx.ccx();
109     let llunitty = type_of::type_of(ccx, unit_ty);
110     let unit_sz = nonzero_llsize_of(ccx, llunitty);
111
112     let fill = Mul(bcx, C_uint(ccx, elts), unit_sz);
113     let alloc = if elts < 4u { Mul(bcx, C_int(ccx, 4), unit_sz) }
114                 else { fill };
115     let Result {bcx: bcx, val: vptr} =
116         alloc_raw(bcx, unit_ty, fill, alloc, heap);
117     return rslt(bcx, vptr);
118 }
119
120 pub fn duplicate_uniq(bcx: block, vptr: ValueRef, vec_ty: ty::t) -> Result {
121     let _icx = bcx.insn_ctxt("tvec::duplicate_uniq");
122
123     let fill = get_fill(bcx, get_bodyptr(bcx, vptr));
124     let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
125     let Result {bcx, val: newptr} = alloc_uniq_raw(bcx, unit_ty, fill, fill);
126
127     let data_ptr = get_dataptr(bcx, get_bodyptr(bcx, vptr));
128     let new_data_ptr = get_dataptr(bcx, get_bodyptr(bcx, newptr));
129     base::call_memcpy(bcx, new_data_ptr, data_ptr, fill);
130
131     let bcx = if ty::type_needs_drop(bcx.tcx(), unit_ty) {
132         iter_vec_raw(bcx, new_data_ptr, vec_ty, fill, glue::take_ty)
133     } else { bcx };
134     return rslt(bcx, newptr);
135 }
136
137 pub fn make_drop_glue_unboxed(bcx: block, vptr: ValueRef, vec_ty: ty::t) ->
138    block {
139     let _icx = bcx.insn_ctxt("tvec::make_drop_glue_unboxed");
140     let tcx = bcx.tcx(), unit_ty = ty::sequence_element_type(tcx, vec_ty);
141     if ty::type_needs_drop(tcx, unit_ty) {
142         iter_vec_unboxed(bcx, vptr, vec_ty, glue::drop_ty)
143     } else { bcx }
144 }
145
146 pub struct VecTypes {
147     vec_ty: ty::t,
148     unit_ty: ty::t,
149     llunit_ty: TypeRef,
150     llunit_size: ValueRef
151 }
152
153 pub impl VecTypes {
154     fn to_str(&self, ccx: @CrateContext) -> ~str {
155         fmt!("VecTypes {vec_ty=%s, unit_ty=%s, llunit_ty=%s, llunit_size=%s}",
156              ty_to_str(ccx.tcx, self.vec_ty),
157              ty_to_str(ccx.tcx, self.unit_ty),
158              ty_str(ccx.tn, self.llunit_ty),
159              val_str(ccx.tn, self.llunit_size))
160     }
161 }
162
163 pub fn trans_fixed_vstore(bcx: block,
164                           vstore_expr: @ast::expr,
165                           content_expr: @ast::expr,
166                           dest: expr::Dest)
167                        -> block {
168     //!
169     //
170     // [...] allocates a fixed-size array and moves it around "by value".
171     // In this case, it means that the caller has already given us a location
172     // to store the array of the suitable size, so all we have to do is
173     // generate the content.
174
175     debug!("trans_fixed_vstore(vstore_expr=%s, dest=%?)",
176            bcx.expr_to_str(vstore_expr), dest.to_str(bcx.ccx()));
177     let _indenter = indenter();
178
179     let vt = vec_types_from_expr(bcx, vstore_expr);
180
181     return match dest {
182         Ignore => write_content(bcx, &vt, vstore_expr, content_expr, dest),
183         SaveIn(lldest) => {
184             // lldest will have type *[T x N], but we want the type *T,
185             // so use GEP to convert:
186             let lldest = GEPi(bcx, lldest, [0, 0]);
187             write_content(bcx, &vt, vstore_expr, content_expr, SaveIn(lldest))
188         }
189     };
190 }
191
192 pub fn trans_slice_vstore(bcx: block,
193                           vstore_expr: @ast::expr,
194                           content_expr: @ast::expr,
195                           dest: expr::Dest)
196                        -> block {
197     //!
198     //
199     // &[...] allocates memory on the stack and writes the values into it,
200     // returning a slice (pair of ptr, len).  &"..." is similar except that
201     // the memory can be statically allocated.
202
203     let ccx = bcx.ccx();
204
205     debug!("trans_slice_vstore(vstore_expr=%s, dest=%s)",
206            bcx.expr_to_str(vstore_expr), dest.to_str(ccx));
207     let _indenter = indenter();
208
209     // Handle the &"..." case:
210     match content_expr.node {
211         ast::expr_lit(@codemap::spanned {node: ast::lit_str(s), span: _}) => {
212             return trans_lit_str(bcx, content_expr, s, dest);
213         }
214         _ => {}
215     }
216
217     // Handle the &[...] case:
218     let vt = vec_types_from_expr(bcx, vstore_expr);
219     let count = elements_required(bcx, content_expr);
220     debug!("vt=%s, count=%?", vt.to_str(ccx), count);
221
222     // Make a fixed-length backing array and allocate it on the stack.
223     let llcount = C_uint(ccx, count);
224     let llfixed = base::arrayalloca(bcx, vt.llunit_ty, llcount);
225
226     // Arrange for the backing array to be cleaned up.
227     let fixed_ty = ty::mk_evec(bcx.tcx(),
228                                ty::mt {ty: vt.unit_ty, mutbl: ast::m_mutbl},
229                                ty::vstore_fixed(count));
230     let llfixed_ty = T_ptr(type_of::type_of(bcx.ccx(), fixed_ty));
231     let llfixed_casted = BitCast(bcx, llfixed, llfixed_ty);
232     add_clean(bcx, llfixed_casted, fixed_ty);
233
234     // Generate the content into the backing array.
235     let bcx = write_content(bcx, &vt, vstore_expr,
236                             content_expr, SaveIn(llfixed));
237
238     // Finally, create the slice pair itself.
239     match dest {
240         Ignore => {}
241         SaveIn(lldest) => {
242             Store(bcx, llfixed, GEPi(bcx, lldest, [0u, abi::slice_elt_base]));
243             let lllen = Mul(bcx, llcount, vt.llunit_size);
244             Store(bcx, lllen, GEPi(bcx, lldest, [0u, abi::slice_elt_len]));
245         }
246     }
247
248     return bcx;
249 }
250
251 pub fn trans_lit_str(bcx: block,
252                      lit_expr: @ast::expr,
253                      str_lit: @~str,
254                      dest: Dest)
255                   -> block {
256     //!
257     //
258     // Literal strings translate to slices into static memory.  This is
259     // different from trans_slice_vstore() above because it does need to copy
260     // the content anywhere.
261
262     debug!("trans_lit_str(lit_expr=%s, dest=%s)",
263            bcx.expr_to_str(lit_expr),
264            dest.to_str(bcx.ccx()));
265     let _indenter = indenter();
266
267     match dest {
268         Ignore => bcx,
269         SaveIn(lldest) => {
270             unsafe {
271                 let bytes = str_lit.len() + 1; // count null-terminator too
272                 let llbytes = C_uint(bcx.ccx(), bytes);
273                 let llcstr = C_cstr(bcx.ccx(), str_lit);
274                 let llcstr = llvm::LLVMConstPointerCast(llcstr,
275                                                         T_ptr(T_i8()));
276                 Store(bcx,
277                       llcstr,
278                       GEPi(bcx, lldest, [0u, abi::slice_elt_base]));
279                 Store(bcx,
280                       llbytes,
281                       GEPi(bcx, lldest, [0u, abi::slice_elt_len]));
282                 bcx
283             }
284         }
285     }
286 }
287
288
289 pub fn trans_uniq_or_managed_vstore(bcx: block,
290                                     heap: heap,
291                                     vstore_expr: @ast::expr,
292                                     content_expr: @ast::expr) -> DatumBlock {
293     //!
294     //
295     // @[...] or ~[...] (also @"..." or ~"...") allocate boxes in the
296     // appropriate heap and write the array elements into them.
297
298     debug!("trans_uniq_or_managed_vstore(vstore_expr=%s, heap=%?)",
299            bcx.expr_to_str(vstore_expr), heap);
300     let _indenter = indenter();
301
302     // Handle ~"".
303     match heap {
304         heap_exchange => {
305             match content_expr.node {
306                 ast::expr_lit(@codemap::spanned {
307                     node: ast::lit_str(s), _
308                 }) => {
309                     let llptrval = C_cstr(bcx.ccx(), s);
310                     let llptrval = PointerCast(bcx, llptrval, T_ptr(T_i8()));
311                     let llsizeval = C_uint(bcx.ccx(), s.len());
312                     let typ = ty::mk_estr(bcx.tcx(), ty::vstore_uniq);
313                     let lldestval = scratch_datum(bcx, typ, false);
314                     let bcx = callee::trans_lang_call(
315                         bcx,
316                         bcx.tcx().lang_items.strdup_uniq_fn(),
317                         ~[ llptrval, llsizeval ],
318                         expr::SaveIn(lldestval.to_ref_llval(bcx)));
319                     return DatumBlock {
320                         bcx: bcx,
321                         datum: lldestval
322                     };
323                 }
324                 _ => {}
325             }
326         }
327         heap_managed | heap_managed_unique => {}
328     }
329
330     let vt = vec_types_from_expr(bcx, vstore_expr);
331     let count = elements_required(bcx, content_expr);
332
333     let Result {bcx, val} = alloc_vec(bcx, vt.unit_ty, count, heap);
334
335     add_clean_free(bcx, val, heap);
336     let dataptr = get_dataptr(bcx, get_bodyptr(bcx, val));
337
338     debug!("alloc_vec() returned val=%s, dataptr=%s",
339            bcx.val_str(val), bcx.val_str(dataptr));
340
341     let bcx = write_content(bcx, &vt, vstore_expr,
342                             content_expr, SaveIn(dataptr));
343
344     revoke_clean(bcx, val);
345
346     return immediate_rvalue_bcx(bcx, val, vt.vec_ty);
347 }
348
349 pub fn write_content(bcx: block,
350                      vt: &VecTypes,
351                      vstore_expr: @ast::expr,
352                      content_expr: @ast::expr,
353                      dest: Dest)
354                   -> block {
355     let _icx = bcx.insn_ctxt("tvec::write_content");
356     let mut bcx = bcx;
357
358     debug!("write_content(vt=%s, dest=%s, vstore_expr=%?)",
359            vt.to_str(bcx.ccx()),
360            dest.to_str(bcx.ccx()),
361            bcx.expr_to_str(vstore_expr));
362     let _indenter = indenter();
363
364     match content_expr.node {
365         ast::expr_lit(@codemap::spanned { node: ast::lit_str(s), _ }) => {
366             match dest {
367                 Ignore => {
368                     return bcx;
369                 }
370                 SaveIn(lldest) => {
371                     let bytes = s.len() + 1; // copy null-terminator too
372                     let llbytes = C_uint(bcx.ccx(), bytes);
373                     let llcstr = C_cstr(bcx.ccx(), s);
374                     base::call_memcpy(bcx, lldest, llcstr, llbytes);
375                     return bcx;
376                 }
377             }
378         }
379         ast::expr_vec(ref elements, _) => {
380             match dest {
381                 Ignore => {
382                     for elements.each |element| {
383                         bcx = expr::trans_into(bcx, *element, Ignore);
384                     }
385                 }
386
387                 SaveIn(lldest) => {
388                     let mut temp_cleanups = ~[];
389                     for elements.eachi |i, element| {
390                         let lleltptr = GEPi(bcx, lldest, [i]);
391                         debug!("writing index %? with lleltptr=%?",
392                                i, bcx.val_str(lleltptr));
393                         bcx = expr::trans_into(bcx, *element,
394                                                SaveIn(lleltptr));
395                         add_clean_temp_mem(bcx, lleltptr, vt.unit_ty);
396                         temp_cleanups.push(lleltptr);
397                     }
398                     for vec::each(temp_cleanups) |cleanup| {
399                         revoke_clean(bcx, *cleanup);
400                     }
401                 }
402             }
403             return bcx;
404         }
405         ast::expr_repeat(element, count_expr, _) => {
406             match dest {
407                 Ignore => {
408                     return expr::trans_into(bcx, element, Ignore);
409                 }
410                 SaveIn(lldest) => {
411                     let count = ty::eval_repeat_count(bcx.tcx(), count_expr);
412                     if count == 0 {
413                         return bcx;
414                     }
415
416                     // Some cleanup would be required in the case in which failure happens
417                     // during a copy. But given that copy constructors are not overridable,
418                     // this can only happen as a result of OOM. So we just skip out on the
419                     // cleanup since things would *probably* be broken at that point anyways.
420
421                     let elem = unpack_datum!(bcx, {
422                         expr::trans_to_datum(bcx, element)
423                     });
424
425                     let next_bcx = sub_block(bcx, ~"expr_repeat: while next");
426                     let loop_bcx = loop_scope_block(bcx, next_bcx, None, ~"expr_repeat", None);
427                     let cond_bcx = scope_block(loop_bcx, None, ~"expr_repeat: loop cond");
428                     let set_bcx = scope_block(loop_bcx, None, ~"expr_repeat: body: set");
429                     let inc_bcx = scope_block(loop_bcx, None, ~"expr_repeat: body: inc");
430                     Br(bcx, loop_bcx.llbb);
431
432                     let loop_counter = {
433                         // i = 0
434                         let i = alloca(loop_bcx, bcx.ccx().int_type);
435                         Store(loop_bcx, C_uint(bcx.ccx(), 0), i);
436
437                         Br(loop_bcx, cond_bcx.llbb);
438                         i
439                     };
440
441                     { // i < count
442                         let lhs = Load(cond_bcx, loop_counter);
443                         let rhs = C_uint(bcx.ccx(), count);
444                         let cond_val = ICmp(cond_bcx, lib::llvm::IntULT, lhs, rhs);
445
446                         CondBr(cond_bcx, cond_val, set_bcx.llbb, next_bcx.llbb);
447                     }
448
449                     { // v[i] = elem
450                         let i = Load(set_bcx, loop_counter);
451                         let lleltptr = InBoundsGEP(set_bcx, lldest, [i]);
452                         let set_bcx = elem.copy_to(set_bcx, INIT, lleltptr);
453
454                         Br(set_bcx, inc_bcx.llbb);
455                     }
456
457                     { // i += 1
458                         let i = Load(inc_bcx, loop_counter);
459                         let plusone = Add(inc_bcx, i, C_uint(bcx.ccx(), 1));
460                         Store(inc_bcx, plusone, loop_counter);
461
462                         Br(inc_bcx, cond_bcx.llbb);
463                     }
464
465                     return next_bcx;
466
467                 }
468             }
469         }
470         _ => {
471             bcx.tcx().sess.span_bug(content_expr.span,
472                                     ~"Unexpected evec content");
473         }
474     }
475 }
476
477 pub fn vec_types_from_expr(bcx: block, vec_expr: @ast::expr) -> VecTypes {
478     let vec_ty = node_id_type(bcx, vec_expr.id);
479     vec_types(bcx, vec_ty)
480 }
481
482 pub fn vec_types(bcx: block, vec_ty: ty::t) -> VecTypes {
483     let ccx = bcx.ccx();
484     let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
485     let llunit_ty = type_of::type_of(ccx, unit_ty);
486     let llunit_size = nonzero_llsize_of(ccx, llunit_ty);
487
488     VecTypes {vec_ty: vec_ty,
489               unit_ty: unit_ty,
490               llunit_ty: llunit_ty,
491               llunit_size: llunit_size}
492 }
493
494 pub fn elements_required(bcx: block, content_expr: @ast::expr) -> uint {
495     //! Figure out the number of elements we need to store this content
496
497     match content_expr.node {
498         ast::expr_lit(@codemap::spanned { node: ast::lit_str(s), _ }) => {
499             s.len() + 1
500         },
501         ast::expr_vec(ref es, _) => es.len(),
502         ast::expr_repeat(_, count_expr, _) => {
503             ty::eval_repeat_count(bcx.tcx(), count_expr)
504         }
505         _ => bcx.tcx().sess.span_bug(content_expr.span,
506                                      ~"Unexpected evec content")
507     }
508 }
509
510 pub fn get_base_and_len(bcx: block,
511                         llval: ValueRef,
512                         vec_ty: ty::t) -> (ValueRef, ValueRef) {
513     //!
514     //
515     // Converts a vector into the slice pair.  The vector should be stored in
516     // `llval` which should be either immediate or by-ref as appropriate for
517     // the vector type.  If you have a datum, you would probably prefer to
518     // call `Datum::get_base_and_len()` which will handle any conversions for
519     // you.
520
521     let ccx = bcx.ccx();
522     let vt = vec_types(bcx, vec_ty);
523
524     let vstore = match ty::get(vt.vec_ty).sty {
525       ty::ty_estr(vst) | ty::ty_evec(_, vst) => vst,
526       _ => ty::vstore_uniq
527     };
528
529     match vstore {
530         ty::vstore_fixed(n) => {
531             let base = GEPi(bcx, llval, [0u, 0u]);
532             let n = if ty::type_is_str(vec_ty) { n + 1u } else { n };
533             let len = Mul(bcx, C_uint(ccx, n), vt.llunit_size);
534             (base, len)
535         }
536         ty::vstore_slice(_) => {
537             let base = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_base]));
538             let len = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_len]));
539             (base, len)
540         }
541         ty::vstore_uniq | ty::vstore_box => {
542             let body = get_bodyptr(bcx, llval);
543             (get_dataptr(bcx, body), get_fill(bcx, body))
544         }
545     }
546 }
547
548 pub type val_and_ty_fn = @fn(block, ValueRef, ty::t) -> Result;
549
550 pub type iter_vec_block<'self> = &'self fn(block, ValueRef, ty::t) -> block;
551
552 pub fn iter_vec_raw(bcx: block, data_ptr: ValueRef, vec_ty: ty::t,
553                     fill: ValueRef, f: iter_vec_block) -> block {
554     let _icx = bcx.insn_ctxt("tvec::iter_vec_raw");
555
556     let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
557
558     // Calculate the last pointer address we want to handle.
559     // FIXME (#3729): Optimize this when the size of the unit type is
560     // statically known to not use pointer casts, which tend to confuse
561     // LLVM.
562     let data_end_ptr = pointer_add(bcx, data_ptr, fill);
563
564     // Now perform the iteration.
565     let header_bcx = base::sub_block(bcx, ~"iter_vec_loop_header");
566     Br(bcx, header_bcx.llbb);
567     let data_ptr =
568         Phi(header_bcx, val_ty(data_ptr), ~[data_ptr], ~[bcx.llbb]);
569     let not_yet_at_end =
570         ICmp(header_bcx, lib::llvm::IntULT, data_ptr, data_end_ptr);
571     let body_bcx = base::sub_block(header_bcx, ~"iter_vec_loop_body");
572     let next_bcx = base::sub_block(header_bcx, ~"iter_vec_next");
573     CondBr(header_bcx, not_yet_at_end, body_bcx.llbb, next_bcx.llbb);
574     let body_bcx = f(body_bcx, data_ptr, unit_ty);
575     AddIncomingToPhi(data_ptr, InBoundsGEP(body_bcx, data_ptr,
576                                            ~[C_int(bcx.ccx(), 1)]),
577                      body_bcx.llbb);
578     Br(body_bcx, header_bcx.llbb);
579     return next_bcx;
580
581 }
582
583 pub fn iter_vec_uniq(bcx: block, vptr: ValueRef, vec_ty: ty::t,
584                      fill: ValueRef, f: iter_vec_block) -> block {
585     let _icx = bcx.insn_ctxt("tvec::iter_vec_uniq");
586     let data_ptr = get_dataptr(bcx, get_bodyptr(bcx, vptr));
587     iter_vec_raw(bcx, data_ptr, vec_ty, fill, f)
588 }
589
590 pub fn iter_vec_unboxed(bcx: block, body_ptr: ValueRef, vec_ty: ty::t,
591                         f: iter_vec_block) -> block {
592     let _icx = bcx.insn_ctxt("tvec::iter_vec_unboxed");
593     let fill = get_fill(bcx, body_ptr);
594     let dataptr = get_dataptr(bcx, body_ptr);
595     return iter_vec_raw(bcx, dataptr, vec_ty, fill, f);
596 }
597
598 //
599 // Local Variables:
600 // mode: rust
601 // fill-column: 78;
602 // indent-tabs-mode: nil
603 // c-basic-offset: 4
604 // buffer-file-coding-system: utf-8-unix
605 // End:
606 //