]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/tvec.rs
Register new snapshots
[rust.git] / src / librustc / middle / trans / tvec.rs
1 // Copyright 2012-2014 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 #![allow(non_camel_case_types)]
12
13 use back::abi;
14 use lib;
15 use lib::llvm::{llvm, ValueRef};
16 use middle::lang_items::StrDupUniqFnLangItem;
17 use middle::trans::base::*;
18 use middle::trans::base;
19 use middle::trans::build::*;
20 use middle::trans::callee;
21 use middle::trans::cleanup;
22 use middle::trans::cleanup::CleanupMethods;
23 use middle::trans::common::*;
24 use middle::trans::datum::*;
25 use middle::trans::expr::{Dest, Ignore, SaveIn};
26 use middle::trans::expr;
27 use middle::trans::glue;
28 use middle::trans::machine::{llsize_of, nonzero_llsize_of, llsize_of_alloc};
29 use middle::trans::type_::Type;
30 use middle::trans::type_of;
31 use middle::ty;
32 use util::ppaux::ty_to_str;
33
34 use syntax::ast;
35 use syntax::parse::token::InternedString;
36
37 pub fn get_fill(bcx: &Block, vptr: ValueRef) -> ValueRef {
38     let _icx = push_ctxt("tvec::get_fill");
39     Load(bcx, GEPi(bcx, vptr, [0u, abi::vec_elt_fill]))
40 }
41
42 pub fn get_dataptr(bcx: &Block, vptr: ValueRef) -> ValueRef {
43     let _icx = push_ctxt("tvec::get_dataptr");
44     GEPi(bcx, vptr, [0u, abi::vec_elt_elems, 0u])
45 }
46
47 pub fn pointer_add_byte(bcx: &Block, ptr: ValueRef, bytes: ValueRef) -> ValueRef {
48     let _icx = push_ctxt("tvec::pointer_add_byte");
49     let old_ty = val_ty(ptr);
50     let bptr = PointerCast(bcx, ptr, Type::i8p(bcx.ccx()));
51     return PointerCast(bcx, InBoundsGEP(bcx, bptr, [bytes]), old_ty);
52 }
53
54 pub fn make_drop_glue_unboxed<'a>(
55                               bcx: &'a Block<'a>,
56                               vptr: ValueRef,
57                               unit_ty: ty::t)
58                               -> &'a Block<'a> {
59     let _icx = push_ctxt("tvec::make_drop_glue_unboxed");
60     let tcx = bcx.tcx();
61     if ty::type_needs_drop(tcx, unit_ty) {
62         let fill = get_fill(bcx, vptr);
63         let dataptr = get_dataptr(bcx, vptr);
64         iter_vec_raw(bcx, dataptr, unit_ty, fill, glue::drop_ty)
65     } else { bcx }
66 }
67
68 pub struct VecTypes {
69     pub unit_ty: ty::t,
70     pub llunit_ty: Type,
71     pub llunit_size: ValueRef,
72     pub llunit_alloc_size: u64
73 }
74
75 impl VecTypes {
76     pub fn to_str(&self, ccx: &CrateContext) -> String {
77         format!("VecTypes {{unit_ty={}, llunit_ty={}, \
78                  llunit_size={}, llunit_alloc_size={}}}",
79                 ty_to_str(ccx.tcx(), self.unit_ty),
80                 ccx.tn.type_to_str(self.llunit_ty),
81                 ccx.tn.val_to_str(self.llunit_size),
82                 self.llunit_alloc_size)
83     }
84 }
85
86 pub fn trans_fixed_vstore<'a>(
87                           bcx: &'a Block<'a>,
88                           vstore_expr: &ast::Expr,
89                           content_expr: &ast::Expr,
90                           dest: expr::Dest)
91                           -> &'a Block<'a> {
92     //!
93     //
94     // [...] allocates a fixed-size array and moves it around "by value".
95     // In this case, it means that the caller has already given us a location
96     // to store the array of the suitable size, so all we have to do is
97     // generate the content.
98
99     debug!("trans_fixed_vstore(vstore_expr={}, dest={:?})",
100            bcx.expr_to_str(vstore_expr), dest.to_str(bcx.ccx()));
101
102     let vt = vec_types_from_expr(bcx, vstore_expr);
103
104     return match dest {
105         Ignore => write_content(bcx, &vt, vstore_expr, content_expr, dest),
106         SaveIn(lldest) => {
107             // lldest will have type *[T x N], but we want the type *T,
108             // so use GEP to convert:
109             let lldest = GEPi(bcx, lldest, [0, 0]);
110             write_content(bcx, &vt, vstore_expr, content_expr, SaveIn(lldest))
111         }
112     };
113 }
114
115 pub fn trans_slice_vstore<'a>(
116                           bcx: &'a Block<'a>,
117                           vstore_expr: &ast::Expr,
118                           content_expr: &ast::Expr,
119                           dest: expr::Dest)
120                           -> &'a Block<'a> {
121     /*!
122      * &[...] allocates memory on the stack and writes the values into it,
123      * returning a slice (pair of ptr, len).  &"..." is similar except that
124      * the memory can be statically allocated.
125      */
126
127     let fcx = bcx.fcx;
128     let ccx = fcx.ccx;
129     let mut bcx = bcx;
130
131     debug!("trans_slice_vstore(vstore_expr={}, dest={})",
132            bcx.expr_to_str(vstore_expr), dest.to_str(ccx));
133
134     // Handle the &"..." case:
135     match content_expr.node {
136         ast::ExprLit(lit) => {
137             match lit.node {
138                 ast::LitStr(ref s, _) => {
139                     return trans_lit_str(bcx,
140                                          content_expr,
141                                          s.clone(),
142                                          dest)
143                 }
144                 _ => {}
145             }
146         }
147         _ => {}
148     }
149
150     // Handle the &[...] case:
151     let vt = vec_types_from_expr(bcx, vstore_expr);
152     let count = elements_required(bcx, content_expr);
153     debug!("vt={}, count={:?}", vt.to_str(ccx), count);
154
155     let llcount = C_uint(ccx, count);
156     let llfixed;
157     if count == 0 {
158         // Zero-length array: just use NULL as the data pointer
159         llfixed = C_null(vt.llunit_ty.ptr_to());
160     } else {
161         // Make a fixed-length backing array and allocate it on the stack.
162         llfixed = base::arrayalloca(bcx, vt.llunit_ty, llcount);
163
164         // Arrange for the backing array to be cleaned up.
165         let fixed_ty = ty::mk_vec(bcx.tcx(),
166                                   ty::mt {ty: vt.unit_ty,
167                                           mutbl: ast::MutMutable},
168                                   Some(count));
169         let llfixed_ty = type_of::type_of(bcx.ccx(), fixed_ty).ptr_to();
170         let llfixed_casted = BitCast(bcx, llfixed, llfixed_ty);
171         let cleanup_scope = cleanup::temporary_scope(bcx.tcx(), content_expr.id);
172         fcx.schedule_drop_mem(cleanup_scope, llfixed_casted, fixed_ty);
173
174         // Generate the content into the backing array.
175         bcx = write_content(bcx, &vt, vstore_expr,
176                             content_expr, SaveIn(llfixed));
177     }
178
179     // Finally, create the slice pair itself.
180     match dest {
181         Ignore => {}
182         SaveIn(lldest) => {
183             Store(bcx, llfixed, GEPi(bcx, lldest, [0u, abi::slice_elt_base]));
184             Store(bcx, llcount, GEPi(bcx, lldest, [0u, abi::slice_elt_len]));
185         }
186     }
187
188     return bcx;
189 }
190
191 pub fn trans_lit_str<'a>(
192                      bcx: &'a Block<'a>,
193                      lit_expr: &ast::Expr,
194                      str_lit: InternedString,
195                      dest: Dest)
196                      -> &'a Block<'a> {
197     /*!
198      * Literal strings translate to slices into static memory.  This is
199      * different from trans_slice_vstore() above because it does need to copy
200      * the content anywhere.
201      */
202
203     debug!("trans_lit_str(lit_expr={}, dest={})",
204            bcx.expr_to_str(lit_expr),
205            dest.to_str(bcx.ccx()));
206
207     match dest {
208         Ignore => bcx,
209         SaveIn(lldest) => {
210             unsafe {
211                 let bytes = str_lit.get().len();
212                 let llbytes = C_uint(bcx.ccx(), bytes);
213                 let llcstr = C_cstr(bcx.ccx(), str_lit, false);
214                 let llcstr = llvm::LLVMConstPointerCast(llcstr, Type::i8p(bcx.ccx()).to_ref());
215                 Store(bcx, llcstr,
216                       GEPi(bcx, lldest, [0u, abi::slice_elt_base]));
217                 Store(bcx, llbytes,
218                       GEPi(bcx, lldest, [0u, abi::slice_elt_len]));
219                 bcx
220             }
221         }
222     }
223 }
224
225
226 pub fn trans_uniq_vstore<'a>(bcx: &'a Block<'a>,
227                              vstore_expr: &ast::Expr,
228                              content_expr: &ast::Expr)
229                              -> DatumBlock<'a, Expr> {
230     /*!
231      * ~[...] and "...".to_string() allocate boxes in the exchange heap and write
232      * the array elements into them.
233      */
234
235     debug!("trans_uniq_vstore(vstore_expr={})", bcx.expr_to_str(vstore_expr));
236     let fcx = bcx.fcx;
237     let ccx = fcx.ccx;
238
239     // Handle "".to_string().
240     match content_expr.node {
241         ast::ExprLit(lit) => {
242             match lit.node {
243                 ast::LitStr(ref s, _) => {
244                     let llptrval = C_cstr(ccx, (*s).clone(), false);
245                     let llptrval = PointerCast(bcx, llptrval, Type::i8p(ccx));
246                     let llsizeval = C_uint(ccx, s.get().len());
247                     let typ = ty::mk_uniq(bcx.tcx(), ty::mk_str(bcx.tcx()));
248                     let lldestval = rvalue_scratch_datum(bcx,
249                                                          typ,
250                                                          "");
251                     let alloc_fn = langcall(bcx,
252                                             Some(lit.span),
253                                             "",
254                                             StrDupUniqFnLangItem);
255                     let bcx = callee::trans_lang_call(
256                         bcx,
257                         alloc_fn,
258                         [ llptrval, llsizeval ],
259                         Some(expr::SaveIn(lldestval.val))).bcx;
260                     return DatumBlock::new(bcx, lldestval).to_expr_datumblock();
261                 }
262                 _ => {}
263             }
264         }
265         _ => {}
266     }
267
268     let vec_ty = node_id_type(bcx, vstore_expr.id);
269     let vt = vec_types(bcx, ty::sequence_element_type(bcx.tcx(), vec_ty));
270     let count = elements_required(bcx, content_expr);
271
272     let llunitty = type_of::type_of(ccx, vt.unit_ty);
273     let unit_sz = nonzero_llsize_of(ccx, llunitty);
274
275     let fill = Mul(bcx, C_uint(ccx, count), unit_sz);
276     let alloc = if count < 4u { Mul(bcx, C_int(ccx, 4), unit_sz) }
277     else { fill };
278
279     let vecsize = Add(bcx, alloc, llsize_of(ccx, ccx.opaque_vec_type));
280
281     // ~[T] is not going to be changed to support alignment, since it's obsolete.
282     let align = C_uint(ccx, 8);
283     let Result { bcx: bcx, val: val } = malloc_raw_dyn(bcx, vec_ty, vecsize, align);
284     Store(bcx, fill, GEPi(bcx, val, [0u, abi::vec_elt_fill]));
285     Store(bcx, alloc, GEPi(bcx, val, [0u, abi::vec_elt_alloc]));
286
287     // Create a temporary scope lest execution should fail while
288     // constructing the vector.
289     let temp_scope = fcx.push_custom_cleanup_scope();
290
291     // FIXME: #13994: the old `Box<[T]> will not support sized deallocation, this is a placeholder
292     let content_ty = vt.unit_ty;
293     fcx.schedule_free_value(cleanup::CustomScope(temp_scope),
294                             val, cleanup::HeapExchange, content_ty);
295
296     let dataptr = get_dataptr(bcx, val);
297
298     debug!("alloc_uniq_vec() returned val={}, dataptr={}",
299            bcx.val_to_str(val), bcx.val_to_str(dataptr));
300
301     let bcx = write_content(bcx, &vt, vstore_expr,
302                             content_expr, SaveIn(dataptr));
303
304     fcx.pop_custom_cleanup_scope(temp_scope);
305
306     immediate_rvalue_bcx(bcx, val, vec_ty).to_expr_datumblock()
307 }
308
309 pub fn write_content<'a>(
310                      bcx: &'a Block<'a>,
311                      vt: &VecTypes,
312                      vstore_expr: &ast::Expr,
313                      content_expr: &ast::Expr,
314                      dest: Dest)
315                      -> &'a Block<'a> {
316     let _icx = push_ctxt("tvec::write_content");
317     let fcx = bcx.fcx;
318     let mut bcx = bcx;
319
320     debug!("write_content(vt={}, dest={}, vstore_expr={:?})",
321            vt.to_str(bcx.ccx()),
322            dest.to_str(bcx.ccx()),
323            bcx.expr_to_str(vstore_expr));
324
325     match content_expr.node {
326         ast::ExprLit(lit) => {
327             match lit.node {
328                 ast::LitStr(ref s, _) => {
329                     match dest {
330                         Ignore => return bcx,
331                         SaveIn(lldest) => {
332                             let bytes = s.get().len();
333                             let llbytes = C_uint(bcx.ccx(), bytes);
334                             let llcstr = C_cstr(bcx.ccx(), (*s).clone(), false);
335                             base::call_memcpy(bcx,
336                                               lldest,
337                                               llcstr,
338                                               llbytes,
339                                               1);
340                             return bcx;
341                         }
342                     }
343                 }
344                 _ => {
345                     bcx.tcx().sess.span_bug(content_expr.span,
346                                             "unexpected evec content");
347                 }
348             }
349         }
350         ast::ExprVec(ref elements) => {
351             match dest {
352                 Ignore => {
353                     for element in elements.iter() {
354                         bcx = expr::trans_into(bcx, &**element, Ignore);
355                     }
356                 }
357
358                 SaveIn(lldest) => {
359                     let temp_scope = fcx.push_custom_cleanup_scope();
360                     for (i, element) in elements.iter().enumerate() {
361                         let lleltptr = GEPi(bcx, lldest, [i]);
362                         debug!("writing index {:?} with lleltptr={:?}",
363                                i, bcx.val_to_str(lleltptr));
364                         bcx = expr::trans_into(bcx, &**element,
365                                                SaveIn(lleltptr));
366                         fcx.schedule_drop_mem(
367                             cleanup::CustomScope(temp_scope),
368                             lleltptr,
369                             vt.unit_ty);
370                     }
371                     fcx.pop_custom_cleanup_scope(temp_scope);
372                 }
373             }
374             return bcx;
375         }
376         ast::ExprRepeat(ref element, ref count_expr) => {
377             match dest {
378                 Ignore => {
379                     return expr::trans_into(bcx, &**element, Ignore);
380                 }
381                 SaveIn(lldest) => {
382                     let count = ty::eval_repeat_count(bcx.tcx(), &**count_expr);
383                     if count == 0 {
384                         return bcx;
385                     }
386
387                     // Some cleanup would be required in the case in which failure happens
388                     // during a copy. But given that copy constructors are not overridable,
389                     // this can only happen as a result of OOM. So we just skip out on the
390                     // cleanup since things would *probably* be broken at that point anyways.
391
392                     let elem = unpack_datum!(bcx, expr::trans(bcx, &**element));
393                     assert!(!ty::type_moves_by_default(bcx.tcx(), elem.ty));
394
395                     let bcx = iter_vec_loop(bcx, lldest, vt,
396                                   C_uint(bcx.ccx(), count), |set_bcx, lleltptr, _| {
397                         elem.shallow_copy_and_take(set_bcx, lleltptr)
398                     });
399
400                     elem.add_clean_if_rvalue(bcx, element.id);
401                     bcx
402                 }
403             }
404         }
405         _ => {
406             bcx.tcx().sess.span_bug(content_expr.span,
407                                     "unexpected vec content");
408         }
409     }
410 }
411
412 pub fn vec_types_from_expr(bcx: &Block, vec_expr: &ast::Expr) -> VecTypes {
413     let vec_ty = node_id_type(bcx, vec_expr.id);
414     vec_types(bcx, ty::sequence_element_type(bcx.tcx(), vec_ty))
415 }
416
417 pub fn vec_types(bcx: &Block, unit_ty: ty::t) -> VecTypes {
418     let ccx = bcx.ccx();
419     let llunit_ty = type_of::type_of(ccx, unit_ty);
420     let llunit_size = nonzero_llsize_of(ccx, llunit_ty);
421     let llunit_alloc_size = llsize_of_alloc(ccx, llunit_ty);
422
423     VecTypes {
424         unit_ty: unit_ty,
425         llunit_ty: llunit_ty,
426         llunit_size: llunit_size,
427         llunit_alloc_size: llunit_alloc_size
428     }
429 }
430
431 pub fn elements_required(bcx: &Block, content_expr: &ast::Expr) -> uint {
432     //! Figure out the number of elements we need to store this content
433
434     match content_expr.node {
435         ast::ExprLit(lit) => {
436             match lit.node {
437                 ast::LitStr(ref s, _) => s.get().len(),
438                 _ => {
439                     bcx.tcx().sess.span_bug(content_expr.span,
440                                             "unexpected evec content")
441                 }
442             }
443         },
444         ast::ExprVec(ref es) => es.len(),
445         ast::ExprRepeat(_, ref count_expr) => {
446             ty::eval_repeat_count(bcx.tcx(), &**count_expr)
447         }
448         _ => bcx.tcx().sess.span_bug(content_expr.span,
449                                      "unexpected vec content")
450     }
451 }
452
453 pub fn get_fixed_base_and_byte_len(bcx: &Block,
454                                    llval: ValueRef,
455                                    unit_ty: ty::t,
456                                    vec_length: uint)
457                                    -> (ValueRef, ValueRef) {
458     /*!
459      * Converts a fixed-length vector into the slice pair.
460      * The vector should be stored in `llval` which should be by ref.
461      */
462
463     let ccx = bcx.ccx();
464     let vt = vec_types(bcx, unit_ty);
465
466     let base = GEPi(bcx, llval, [0u, 0u]);
467     let len = Mul(bcx, C_uint(ccx, vec_length), vt.llunit_size);
468     (base, len)
469 }
470
471 pub fn get_base_and_len(bcx: &Block,
472                         llval: ValueRef,
473                         vec_ty: ty::t)
474                         -> (ValueRef, ValueRef) {
475     /*!
476      * Converts a vector into the slice pair.  The vector should be
477      * stored in `llval` which should be by-reference.  If you have a
478      * datum, you would probably prefer to call
479      * `Datum::get_base_and_len()` which will handle any conversions
480      * for you.
481      */
482
483     let ccx = bcx.ccx();
484
485     match ty::get(vec_ty).sty {
486         ty::ty_vec(_, Some(n)) => {
487             let base = GEPi(bcx, llval, [0u, 0u]);
488             (base, C_uint(ccx, n))
489         }
490         ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty {
491             ty::ty_vec(_, None) | ty::ty_str => {
492                 assert!(!type_is_immediate(bcx.ccx(), vec_ty));
493                 let base = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_base]));
494                 let count = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_len]));
495                 (base, count)
496             }
497             _ => ccx.sess().bug("unexpected type (ty_rptr) in get_base_and_len"),
498         },
499         ty::ty_uniq(t) => match ty::get(t).sty {
500             ty::ty_vec(_, None) | ty::ty_str => {
501                 assert!(type_is_immediate(bcx.ccx(), vec_ty));
502                 let vt = vec_types(bcx, ty::sequence_element_type(bcx.tcx(), vec_ty));
503                 let body = Load(bcx, llval);
504                 (get_dataptr(bcx, body), UDiv(bcx, get_fill(bcx, body), vt.llunit_size))
505             }
506             _ => ccx.sess().bug("unexpected type (ty_uniq) in get_base_and_len"),
507         },
508         _ => ccx.sess().bug("unexpected type in get_base_and_len"),
509     }
510 }
511
512 pub type iter_vec_block<'r,'b> =
513     |&'b Block<'b>, ValueRef, ty::t|: 'r -> &'b Block<'b>;
514
515 pub fn iter_vec_loop<'r,
516                      'b>(
517                      bcx: &'b Block<'b>,
518                      data_ptr: ValueRef,
519                      vt: &VecTypes,
520                      count: ValueRef,
521                      f: iter_vec_block<'r,'b>)
522                      -> &'b Block<'b> {
523     let _icx = push_ctxt("tvec::iter_vec_loop");
524     let fcx = bcx.fcx;
525
526     let next_bcx = fcx.new_temp_block("expr_repeat: while next");
527     let loop_bcx = fcx.new_temp_block("expr_repeat");
528     let cond_bcx = fcx.new_temp_block("expr_repeat: loop cond");
529     let body_bcx = fcx.new_temp_block("expr_repeat: body: set");
530     let inc_bcx = fcx.new_temp_block("expr_repeat: body: inc");
531     Br(bcx, loop_bcx.llbb);
532
533     let loop_counter = {
534         // i = 0
535         let i = alloca(loop_bcx, bcx.ccx().int_type, "__i");
536         Store(loop_bcx, C_uint(bcx.ccx(), 0), i);
537
538         Br(loop_bcx, cond_bcx.llbb);
539         i
540     };
541
542     { // i < count
543         let lhs = Load(cond_bcx, loop_counter);
544         let rhs = count;
545         let cond_val = ICmp(cond_bcx, lib::llvm::IntULT, lhs, rhs);
546
547         CondBr(cond_bcx, cond_val, body_bcx.llbb, next_bcx.llbb);
548     }
549
550     { // loop body
551         let i = Load(body_bcx, loop_counter);
552         let lleltptr = if vt.llunit_alloc_size == 0 {
553             data_ptr
554         } else {
555             InBoundsGEP(body_bcx, data_ptr, [i])
556         };
557         let body_bcx = f(body_bcx, lleltptr, vt.unit_ty);
558
559         Br(body_bcx, inc_bcx.llbb);
560     }
561
562     { // i += 1
563         let i = Load(inc_bcx, loop_counter);
564         let plusone = Add(inc_bcx, i, C_uint(bcx.ccx(), 1));
565         Store(inc_bcx, plusone, loop_counter);
566
567         Br(inc_bcx, cond_bcx.llbb);
568     }
569
570     next_bcx
571 }
572
573 pub fn iter_vec_raw<'r,
574                     'b>(
575                     bcx: &'b Block<'b>,
576                     data_ptr: ValueRef,
577                     unit_ty: ty::t,
578                     fill: ValueRef,
579                     f: iter_vec_block<'r,'b>)
580                     -> &'b Block<'b> {
581     let _icx = push_ctxt("tvec::iter_vec_raw");
582     let fcx = bcx.fcx;
583
584     let vt = vec_types(bcx, unit_ty);
585     if vt.llunit_alloc_size == 0 {
586         // Special-case vectors with elements of size 0  so they don't go out of bounds (#9890)
587         iter_vec_loop(bcx, data_ptr, &vt, fill, f)
588     } else {
589         // Calculate the last pointer address we want to handle.
590         // FIXME (#3729): Optimize this when the size of the unit type is
591         // statically known to not use pointer casts, which tend to confuse
592         // LLVM.
593         let data_end_ptr = pointer_add_byte(bcx, data_ptr, fill);
594
595         // Now perform the iteration.
596         let header_bcx = fcx.new_temp_block("iter_vec_loop_header");
597         Br(bcx, header_bcx.llbb);
598         let data_ptr =
599             Phi(header_bcx, val_ty(data_ptr), [data_ptr], [bcx.llbb]);
600         let not_yet_at_end =
601             ICmp(header_bcx, lib::llvm::IntULT, data_ptr, data_end_ptr);
602         let body_bcx = fcx.new_temp_block("iter_vec_loop_body");
603         let next_bcx = fcx.new_temp_block("iter_vec_next");
604         CondBr(header_bcx, not_yet_at_end, body_bcx.llbb, next_bcx.llbb);
605         let body_bcx = f(body_bcx, data_ptr, vt.unit_ty);
606         AddIncomingToPhi(data_ptr, InBoundsGEP(body_bcx, data_ptr,
607                                                [C_int(bcx.ccx(), 1)]),
608                          body_bcx.llbb);
609         Br(body_bcx, header_bcx.llbb);
610         next_bcx
611     }
612 }