]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans/datum.rs
8b52732f4ee972c7718cd4a26d5d1779d5e39b28
[rust.git] / src / librustc_trans / trans / datum.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 //! See the section on datums in `doc.rs` for an overview of what Datums are and how they are
12 //! intended to be used.
13
14 pub use self::Expr::*;
15 pub use self::RvalueMode::*;
16
17 use llvm::ValueRef;
18 use trans::base::*;
19 use trans::build::Load;
20 use trans::common::*;
21 use trans::cleanup;
22 use trans::cleanup::CleanupMethods;
23 use trans::expr;
24 use trans::tvec;
25 use trans::type_of;
26 use middle::ty::{self, Ty};
27 use util::ppaux::{ty_to_string};
28
29 use std::fmt;
30 use syntax::ast;
31 use syntax::codemap::DUMMY_SP;
32
33 /// A `Datum` encapsulates the result of evaluating an expression.  It
34 /// describes where the value is stored, what Rust type the value has,
35 /// whether it is addressed by reference, and so forth. Please refer
36 /// the section on datums in `doc.rs` for more details.
37 #[derive(Clone, Copy)]
38 pub struct Datum<'tcx, K> {
39     /// The llvm value.  This is either a pointer to the Rust value or
40     /// the value itself, depending on `kind` below.
41     pub val: ValueRef,
42
43     /// The rust type of the value.
44     pub ty: Ty<'tcx>,
45
46     /// Indicates whether this is by-ref or by-value.
47     pub kind: K,
48 }
49
50 pub struct DatumBlock<'blk, 'tcx: 'blk, K> {
51     pub bcx: Block<'blk, 'tcx>,
52     pub datum: Datum<'tcx, K>,
53 }
54
55 #[derive(Show)]
56 pub enum Expr {
57     /// a fresh value that was produced and which has no cleanup yet
58     /// because it has not yet "landed" into its permanent home
59     RvalueExpr(Rvalue),
60
61     /// `val` is a pointer into memory for which a cleanup is scheduled
62     /// (and thus has type *T). If you move out of an Lvalue, you must
63     /// zero out the memory (FIXME #5016).
64     LvalueExpr,
65 }
66
67 #[derive(Clone, Copy, Show)]
68 pub struct Lvalue;
69
70 #[derive(Show)]
71 pub struct Rvalue {
72     pub mode: RvalueMode
73 }
74
75 impl Rvalue {
76     pub fn new(m: RvalueMode) -> Rvalue {
77         Rvalue { mode: m }
78     }
79 }
80
81 // Make Datum linear for more type safety.
82 impl Drop for Rvalue {
83     fn drop(&mut self) { }
84 }
85
86 #[derive(Copy, PartialEq, Eq, Hash, Show)]
87 pub enum RvalueMode {
88     /// `val` is a pointer to the actual value (and thus has type *T)
89     ByRef,
90
91     /// `val` is the actual value (*only used for immediates* like ints, ptrs)
92     ByValue,
93 }
94
95 pub fn immediate_rvalue<'tcx>(val: ValueRef, ty: Ty<'tcx>) -> Datum<'tcx, Rvalue> {
96     return Datum::new(val, ty, Rvalue::new(ByValue));
97 }
98
99 pub fn immediate_rvalue_bcx<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
100                                         val: ValueRef,
101                                         ty: Ty<'tcx>)
102                                         -> DatumBlock<'blk, 'tcx, Rvalue> {
103     return DatumBlock::new(bcx, immediate_rvalue(val, ty))
104 }
105
106
107 /// Allocates temporary space on the stack using alloca() and returns a by-ref Datum pointing to
108 /// it. The memory will be dropped upon exit from `scope`. The callback `populate` should
109 /// initialize the memory. If `zero` is true, the space will be zeroed when it is allocated; this
110 /// is not necessary unless `bcx` does not dominate the end of `scope`.
111 pub fn lvalue_scratch_datum<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>,
112                                               ty: Ty<'tcx>,
113                                               name: &str,
114                                               zero: bool,
115                                               scope: cleanup::ScopeId,
116                                               arg: A,
117                                               populate: F)
118                                               -> DatumBlock<'blk, 'tcx, Lvalue> where
119     F: FnOnce(A, Block<'blk, 'tcx>, ValueRef) -> Block<'blk, 'tcx>,
120 {
121     let scratch = if zero {
122         alloca_zeroed(bcx, ty, name)
123     } else {
124         let llty = type_of::type_of(bcx.ccx(), ty);
125         alloca(bcx, llty, name)
126     };
127
128     // Subtle. Populate the scratch memory *before* scheduling cleanup.
129     let bcx = populate(arg, bcx, scratch);
130     bcx.fcx.schedule_lifetime_end(scope, scratch);
131     bcx.fcx.schedule_drop_mem(scope, scratch, ty);
132
133     DatumBlock::new(bcx, Datum::new(scratch, ty, Lvalue))
134 }
135
136 /// Allocates temporary space on the stack using alloca() and returns a by-ref Datum pointing to
137 /// it.  If `zero` is true, the space will be zeroed when it is allocated; this is normally not
138 /// necessary, but in the case of automatic rooting in match statements it is possible to have
139 /// temporaries that may not get initialized if a certain arm is not taken, so we must zero them.
140 /// You must arrange any cleanups etc yourself!
141 pub fn rvalue_scratch_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
142                                         ty: Ty<'tcx>,
143                                         name: &str)
144                                         -> Datum<'tcx, Rvalue> {
145     let llty = type_of::type_of(bcx.ccx(), ty);
146     let scratch = alloca(bcx, llty, name);
147     Datum::new(scratch, ty, Rvalue::new(ByRef))
148 }
149
150 /// Indicates the "appropriate" mode for this value, which is either by ref or by value, depending
151 /// on whether type is immediate or not.
152 pub fn appropriate_rvalue_mode<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
153                                          ty: Ty<'tcx>) -> RvalueMode {
154     if type_is_immediate(ccx, ty) {
155         ByValue
156     } else {
157         ByRef
158     }
159 }
160
161 fn add_rvalue_clean<'a, 'tcx>(mode: RvalueMode,
162                               fcx: &FunctionContext<'a, 'tcx>,
163                               scope: cleanup::ScopeId,
164                               val: ValueRef,
165                               ty: Ty<'tcx>) {
166     match mode {
167         ByValue => { fcx.schedule_drop_immediate(scope, val, ty); }
168         ByRef => {
169             fcx.schedule_lifetime_end(scope, val);
170             fcx.schedule_drop_mem(scope, val, ty);
171         }
172     }
173 }
174
175 pub trait KindOps {
176
177     /// Take appropriate action after the value in `datum` has been
178     /// stored to a new location.
179     fn post_store<'blk, 'tcx>(&self,
180                               bcx: Block<'blk, 'tcx>,
181                               val: ValueRef,
182                               ty: Ty<'tcx>)
183                               -> Block<'blk, 'tcx>;
184
185     /// True if this mode is a reference mode, meaning that the datum's
186     /// val field is a pointer to the actual value
187     fn is_by_ref(&self) -> bool;
188
189     /// Converts to an Expr kind
190     fn to_expr_kind(self) -> Expr;
191
192 }
193
194 impl KindOps for Rvalue {
195     fn post_store<'blk, 'tcx>(&self,
196                               bcx: Block<'blk, 'tcx>,
197                               _val: ValueRef,
198                               _ty: Ty<'tcx>)
199                               -> Block<'blk, 'tcx> {
200         // No cleanup is scheduled for an rvalue, so we don't have
201         // to do anything after a move to cancel or duplicate it.
202         bcx
203     }
204
205     fn is_by_ref(&self) -> bool {
206         self.mode == ByRef
207     }
208
209     fn to_expr_kind(self) -> Expr {
210         RvalueExpr(self)
211     }
212 }
213
214 impl KindOps for Lvalue {
215     /// If an lvalue is moved, we must zero out the memory in which it resides so as to cancel
216     /// cleanup. If an @T lvalue is copied, we must increment the reference count.
217     fn post_store<'blk, 'tcx>(&self,
218                               bcx: Block<'blk, 'tcx>,
219                               val: ValueRef,
220                               ty: Ty<'tcx>)
221                               -> Block<'blk, 'tcx> {
222         if type_needs_drop(bcx.tcx(), ty) {
223             // cancel cleanup of affine values by zeroing out
224             let () = zero_mem(bcx, val, ty);
225             bcx
226         } else {
227             bcx
228         }
229     }
230
231     fn is_by_ref(&self) -> bool {
232         true
233     }
234
235     fn to_expr_kind(self) -> Expr {
236         LvalueExpr
237     }
238 }
239
240 impl KindOps for Expr {
241     fn post_store<'blk, 'tcx>(&self,
242                               bcx: Block<'blk, 'tcx>,
243                               val: ValueRef,
244                               ty: Ty<'tcx>)
245                               -> Block<'blk, 'tcx> {
246         match *self {
247             LvalueExpr => Lvalue.post_store(bcx, val, ty),
248             RvalueExpr(ref r) => r.post_store(bcx, val, ty),
249         }
250     }
251
252     fn is_by_ref(&self) -> bool {
253         match *self {
254             LvalueExpr => Lvalue.is_by_ref(),
255             RvalueExpr(ref r) => r.is_by_ref()
256         }
257     }
258
259     fn to_expr_kind(self) -> Expr {
260         self
261     }
262 }
263
264 impl<'tcx> Datum<'tcx, Rvalue> {
265     /// Schedules a cleanup for this datum in the given scope. That means that this datum is no
266     /// longer an rvalue datum; hence, this function consumes the datum and returns the contained
267     /// ValueRef.
268     pub fn add_clean<'a>(self,
269                          fcx: &FunctionContext<'a, 'tcx>,
270                          scope: cleanup::ScopeId)
271                          -> ValueRef {
272         add_rvalue_clean(self.kind.mode, fcx, scope, self.val, self.ty);
273         self.val
274     }
275
276     /// Returns an lvalue datum (that is, a by ref datum with cleanup scheduled). If `self` is not
277     /// already an lvalue, cleanup will be scheduled in the temporary scope for `expr_id`.
278     pub fn to_lvalue_datum_in_scope<'blk>(self,
279                                           bcx: Block<'blk, 'tcx>,
280                                           name: &str,
281                                           scope: cleanup::ScopeId)
282                                           -> DatumBlock<'blk, 'tcx, Lvalue> {
283         let fcx = bcx.fcx;
284
285         match self.kind.mode {
286             ByRef => {
287                 add_rvalue_clean(ByRef, fcx, scope, self.val, self.ty);
288                 DatumBlock::new(bcx, Datum::new(self.val, self.ty, Lvalue))
289             }
290
291             ByValue => {
292                 lvalue_scratch_datum(
293                     bcx, self.ty, name, false, scope, self,
294                     |this, bcx, llval| this.store_to(bcx, llval))
295             }
296         }
297     }
298
299     pub fn to_ref_datum<'blk>(self, bcx: Block<'blk, 'tcx>)
300                               -> DatumBlock<'blk, 'tcx, Rvalue> {
301         let mut bcx = bcx;
302         match self.kind.mode {
303             ByRef => DatumBlock::new(bcx, self),
304             ByValue => {
305                 let scratch = rvalue_scratch_datum(bcx, self.ty, "to_ref");
306                 bcx = self.store_to(bcx, scratch.val);
307                 DatumBlock::new(bcx, scratch)
308             }
309         }
310     }
311
312     pub fn to_appropriate_datum<'blk>(self, bcx: Block<'blk, 'tcx>)
313                                       -> DatumBlock<'blk, 'tcx, Rvalue> {
314         match self.appropriate_rvalue_mode(bcx.ccx()) {
315             ByRef => {
316                 self.to_ref_datum(bcx)
317             }
318             ByValue => {
319                 match self.kind.mode {
320                     ByValue => DatumBlock::new(bcx, self),
321                     ByRef => {
322                         let llval = load_ty(bcx, self.val, self.ty);
323                         DatumBlock::new(bcx, Datum::new(llval, self.ty, Rvalue::new(ByValue)))
324                     }
325                 }
326             }
327         }
328     }
329 }
330
331 /// Methods suitable for "expr" datums that could be either lvalues or
332 /// rvalues. These include coercions into lvalues/rvalues but also a number
333 /// of more general operations. (Some of those operations could be moved to
334 /// the more general `impl<K> Datum<K>`, but it's convenient to have them
335 /// here since we can `match self.kind` rather than having to implement
336 /// generic methods in `KindOps`.)
337 impl<'tcx> Datum<'tcx, Expr> {
338     fn match_kind<R, F, G>(self, if_lvalue: F, if_rvalue: G) -> R where
339         F: FnOnce(Datum<'tcx, Lvalue>) -> R,
340         G: FnOnce(Datum<'tcx, Rvalue>) -> R,
341     {
342         let Datum { val, ty, kind } = self;
343         match kind {
344             LvalueExpr => if_lvalue(Datum::new(val, ty, Lvalue)),
345             RvalueExpr(r) => if_rvalue(Datum::new(val, ty, r)),
346         }
347     }
348
349     /// Asserts that this datum *is* an lvalue and returns it.
350     #[allow(dead_code)] // potentially useful
351     pub fn assert_lvalue(self, bcx: Block) -> Datum<'tcx, Lvalue> {
352         self.match_kind(
353             |d| d,
354             |_| bcx.sess().bug("assert_lvalue given rvalue"))
355     }
356
357     pub fn store_to_dest<'blk>(self,
358                                bcx: Block<'blk, 'tcx>,
359                                dest: expr::Dest,
360                                expr_id: ast::NodeId)
361                                -> Block<'blk, 'tcx> {
362         match dest {
363             expr::Ignore => {
364                 self.add_clean_if_rvalue(bcx, expr_id);
365                 bcx
366             }
367             expr::SaveIn(addr) => {
368                 self.store_to(bcx, addr)
369             }
370         }
371     }
372
373     /// Arranges cleanup for `self` if it is an rvalue. Use when you are done working with a value
374     /// that may need drop.
375     pub fn add_clean_if_rvalue<'blk>(self,
376                                      bcx: Block<'blk, 'tcx>,
377                                      expr_id: ast::NodeId) {
378         self.match_kind(
379             |_| { /* Nothing to do, cleanup already arranged */ },
380             |r| {
381                 let scope = cleanup::temporary_scope(bcx.tcx(), expr_id);
382                 r.add_clean(bcx.fcx, scope);
383             })
384     }
385
386     /// Ensures that `self` will get cleaned up, if it is not an lvalue already.
387     pub fn clean<'blk>(self,
388                        bcx: Block<'blk, 'tcx>,
389                        name: &'static str,
390                        expr_id: ast::NodeId)
391                        -> Block<'blk, 'tcx> {
392         self.to_lvalue_datum(bcx, name, expr_id).bcx
393     }
394
395     pub fn to_lvalue_datum<'blk>(self,
396                                  bcx: Block<'blk, 'tcx>,
397                                  name: &str,
398                                  expr_id: ast::NodeId)
399                                  -> DatumBlock<'blk, 'tcx, Lvalue> {
400         debug!("to_lvalue_datum self: {}", self.to_string(bcx.ccx()));
401
402         assert!(lltype_is_sized(bcx.tcx(), self.ty),
403                 "Trying to convert unsized value to lval");
404         self.match_kind(
405             |l| DatumBlock::new(bcx, l),
406             |r| {
407                 let scope = cleanup::temporary_scope(bcx.tcx(), expr_id);
408                 r.to_lvalue_datum_in_scope(bcx, name, scope)
409             })
410     }
411
412     /// Ensures that we have an rvalue datum (that is, a datum with no cleanup scheduled).
413     pub fn to_rvalue_datum<'blk>(self,
414                                  bcx: Block<'blk, 'tcx>,
415                                  name: &'static str)
416                                  -> DatumBlock<'blk, 'tcx, Rvalue> {
417         self.match_kind(
418             |l| {
419                 let mut bcx = bcx;
420                 match l.appropriate_rvalue_mode(bcx.ccx()) {
421                     ByRef => {
422                         let scratch = rvalue_scratch_datum(bcx, l.ty, name);
423                         bcx = l.store_to(bcx, scratch.val);
424                         DatumBlock::new(bcx, scratch)
425                     }
426                     ByValue => {
427                         let v = load_ty(bcx, l.val, l.ty);
428                         bcx = l.kind.post_store(bcx, l.val, l.ty);
429                         DatumBlock::new(bcx, Datum::new(v, l.ty, Rvalue::new(ByValue)))
430                     }
431                 }
432             },
433             |r| DatumBlock::new(bcx, r))
434     }
435
436 }
437
438 /// Methods suitable only for lvalues. These include the various
439 /// operations to extract components out of compound data structures,
440 /// such as extracting the field from a struct or a particular element
441 /// from an array.
442 impl<'tcx> Datum<'tcx, Lvalue> {
443     /// Converts a datum into a by-ref value. The datum type must be one which is always passed by
444     /// reference.
445     pub fn to_llref(self) -> ValueRef {
446         self.val
447     }
448
449     // Extracts a component of a compound data structure (e.g., a field from a
450     // struct). Note that if self is an opened, unsized type then the returned
451     // datum may also be unsized _without the size information_. It is the
452     // callers responsibility to package the result in some way to make a valid
453     // datum in that case (e.g., by making a fat pointer or opened pair).
454     pub fn get_element<'blk, F>(&self, bcx: Block<'blk, 'tcx>, ty: Ty<'tcx>,
455                                 gep: F)
456                                 -> Datum<'tcx, Lvalue> where
457         F: FnOnce(ValueRef) -> ValueRef,
458     {
459         let val = match self.ty.sty {
460             _ if type_is_sized(bcx.tcx(), self.ty) => gep(self.val),
461             ty::ty_open(_) => {
462                 let base = Load(bcx, expr::get_dataptr(bcx, self.val));
463                 gep(base)
464             }
465             _ => bcx.tcx().sess.bug(
466                 &format!("Unexpected unsized type in get_element: {}",
467                         bcx.ty_to_string(self.ty))[])
468         };
469         Datum {
470             val: val,
471             kind: Lvalue,
472             ty: ty,
473         }
474     }
475
476     pub fn get_vec_base_and_len(&self, bcx: Block) -> (ValueRef, ValueRef) {
477         //! Converts a vector into the slice pair.
478
479         tvec::get_base_and_len(bcx, self.val, self.ty)
480     }
481 }
482
483 /// Generic methods applicable to any sort of datum.
484 impl<'tcx, K: KindOps + fmt::Show> Datum<'tcx, K> {
485     pub fn new(val: ValueRef, ty: Ty<'tcx>, kind: K) -> Datum<'tcx, K> {
486         Datum { val: val, ty: ty, kind: kind }
487     }
488
489     pub fn to_expr_datum(self) -> Datum<'tcx, Expr> {
490         let Datum { val, ty, kind } = self;
491         Datum { val: val, ty: ty, kind: kind.to_expr_kind() }
492     }
493
494     /// Moves or copies this value into a new home, as appropriate depending on the type of the
495     /// datum. This method consumes the datum, since it would be incorrect to go on using the datum
496     /// if the value represented is affine (and hence the value is moved).
497     pub fn store_to<'blk>(self,
498                           bcx: Block<'blk, 'tcx>,
499                           dst: ValueRef)
500                           -> Block<'blk, 'tcx> {
501         self.shallow_copy_raw(bcx, dst);
502
503         self.kind.post_store(bcx, self.val, self.ty)
504     }
505
506     /// Helper function that performs a shallow copy of this value into `dst`, which should be a
507     /// pointer to a memory location suitable for `self.ty`. `dst` should contain uninitialized
508     /// memory (either newly allocated, zeroed, or dropped).
509     ///
510     /// This function is private to datums because it leaves memory in an unstable state, where the
511     /// source value has been copied but not zeroed. Public methods are `store_to` (if you no
512     /// longer need the source value) or `shallow_copy` (if you wish the source value to remain
513     /// valid).
514     fn shallow_copy_raw<'blk>(&self,
515                               bcx: Block<'blk, 'tcx>,
516                               dst: ValueRef)
517                               -> Block<'blk, 'tcx> {
518         let _icx = push_ctxt("copy_to_no_check");
519
520         if type_is_zero_size(bcx.ccx(), self.ty) {
521             return bcx;
522         }
523
524         if self.kind.is_by_ref() {
525             memcpy_ty(bcx, dst, self.val, self.ty);
526         } else {
527             store_ty(bcx, self.val, dst, self.ty);
528         }
529
530         return bcx;
531     }
532
533     /// Copies the value into a new location. This function always preserves the existing datum as
534     /// a valid value. Therefore, it does not consume `self` and, also, cannot be applied to affine
535     /// values (since they must never be duplicated).
536     pub fn shallow_copy<'blk>(&self,
537                               bcx: Block<'blk, 'tcx>,
538                               dst: ValueRef)
539                               -> Block<'blk, 'tcx> {
540         /*!
541          * Copies the value into a new location. This function always
542          * preserves the existing datum as a valid value. Therefore,
543          * it does not consume `self` and, also, cannot be applied to
544          * affine values (since they must never be duplicated).
545          */
546
547         assert!(!ty::type_moves_by_default(&ty::empty_parameter_environment(bcx.tcx()),
548                                            DUMMY_SP,
549                                            self.ty));
550         self.shallow_copy_raw(bcx, dst)
551     }
552
553     #[allow(dead_code)] // useful for debugging
554     pub fn to_string<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> String {
555         format!("Datum({}, {}, {:?})",
556                 ccx.tn().val_to_string(self.val),
557                 ty_to_string(ccx.tcx(), self.ty),
558                 self.kind)
559     }
560
561     /// See the `appropriate_rvalue_mode()` function
562     pub fn appropriate_rvalue_mode<'a>(&self, ccx: &CrateContext<'a, 'tcx>)
563                                        -> RvalueMode {
564         appropriate_rvalue_mode(ccx, self.ty)
565     }
566
567     /// Converts `self` into a by-value `ValueRef`. Consumes this datum (i.e., absolves you of
568     /// responsibility to cleanup the value). For this to work, the value must be something
569     /// scalar-ish (like an int or a pointer) which (1) does not require drop glue and (2) is
570     /// naturally passed around by value, and not by reference.
571     pub fn to_llscalarish<'blk>(self, bcx: Block<'blk, 'tcx>) -> ValueRef {
572         assert!(!type_needs_drop(bcx.tcx(), self.ty));
573         assert!(self.appropriate_rvalue_mode(bcx.ccx()) == ByValue);
574         if self.kind.is_by_ref() {
575             load_ty(bcx, self.val, self.ty)
576         } else {
577             self.val
578         }
579     }
580
581     pub fn to_llbool<'blk>(self, bcx: Block<'blk, 'tcx>) -> ValueRef {
582         assert!(ty::type_is_bool(self.ty));
583         self.to_llscalarish(bcx)
584     }
585 }
586
587 impl<'blk, 'tcx, K> DatumBlock<'blk, 'tcx, K> {
588     pub fn new(bcx: Block<'blk, 'tcx>, datum: Datum<'tcx, K>)
589                -> DatumBlock<'blk, 'tcx, K> {
590         DatumBlock { bcx: bcx, datum: datum }
591     }
592 }
593
594 impl<'blk, 'tcx, K: KindOps + fmt::Show> DatumBlock<'blk, 'tcx, K> {
595     pub fn to_expr_datumblock(self) -> DatumBlock<'blk, 'tcx, Expr> {
596         DatumBlock::new(self.bcx, self.datum.to_expr_datum())
597     }
598 }
599
600 impl<'blk, 'tcx> DatumBlock<'blk, 'tcx, Expr> {
601     pub fn store_to_dest(self,
602                          dest: expr::Dest,
603                          expr_id: ast::NodeId) -> Block<'blk, 'tcx> {
604         let DatumBlock { bcx, datum } = self;
605         datum.store_to_dest(bcx, dest, expr_id)
606     }
607
608     pub fn to_llbool(self) -> Result<'blk, 'tcx> {
609         let DatumBlock { datum, bcx } = self;
610         Result::new(bcx, datum.to_llbool(bcx))
611     }
612 }