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.
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.
12 * See the section on datums in `doc.rs` for an overview of what
13 * Datums are and how they are intended to be used.
17 use lib::llvm::ValueRef;
18 use middle::trans::base::*;
19 use middle::trans::build::*;
20 use middle::trans::common::*;
21 use middle::trans::cleanup;
22 use middle::trans::cleanup::CleanupMethods;
23 use middle::trans::expr;
24 use middle::trans::glue;
25 use middle::trans::tvec;
26 use middle::trans::type_of;
27 use middle::trans::write_guard;
29 use util::ppaux::{ty_to_str};
32 use syntax::codemap::Span;
35 * A `Datum` encapsulates the result of evaluating an expression. It
36 * describes where the value is stored, what Rust type the value has,
37 * whether it is addressed by reference, and so forth. Please refer
38 * the section on datums in `doc.rs` for more details.
42 /// The llvm value. This is either a pointer to the Rust value or
43 /// the value itself, depending on `kind` below.
46 /// The rust type of the value.
49 /// Indicates whether this is by-ref or by-value.
53 pub struct DatumBlock<'a, K> {
59 /// a fresh value that was produced and which has no cleanup yet
60 /// because it has not yet "landed" into its permanent home
63 /// `val` is a pointer into memory for which a cleanup is scheduled
64 /// (and thus has type *T). If you move out of an Lvalue, you must
65 /// zero out the memory (FIXME #5016).
76 pub fn Rvalue(m: RvalueMode) -> Rvalue {
80 // Make Datum linear for more type safety.
81 impl Drop for Rvalue {
82 fn drop(&mut self) { }
87 /// `val` is a pointer to the actual value (and thus has type *T)
90 /// `val` is the actual value (*only used for immediates* like ints, ptrs)
94 pub fn Datum<K:KindOps>(val: ValueRef, ty: ty::t, kind: K) -> Datum<K> {
95 Datum { val: val, ty: ty, kind: kind }
98 pub fn DatumBlock<'a, K>(bcx: &'a Block<'a>,
100 -> DatumBlock<'a, K> {
101 DatumBlock { bcx: bcx, datum: datum }
104 pub fn immediate_rvalue(val: ValueRef, ty: ty::t) -> Datum<Rvalue> {
105 return Datum(val, ty, Rvalue(ByValue));
108 pub fn immediate_rvalue_bcx<'a>(bcx: &'a Block<'a>,
111 -> DatumBlock<'a, Rvalue> {
112 return DatumBlock(bcx, immediate_rvalue(val, ty))
116 pub fn lvalue_scratch_datum<'a, A>(bcx: &'a Block<'a>,
120 scope: cleanup::ScopeId,
122 populate: |A, &'a Block<'a>, ValueRef|
124 -> DatumBlock<'a, Lvalue> {
126 * Allocates temporary space on the stack using alloca() and
127 * returns a by-ref Datum pointing to it. The memory will be
128 * dropped upon exit from `scope`. The callback `populate` should
129 * initialize the memory. If `zero` is true, the space will be
130 * zeroed when it is allocated; this is not necessary unless `bcx`
131 * does not dominate the end of `scope`.
134 let llty = type_of::type_of(bcx.ccx(), ty);
135 let scratch = alloca_maybe_zeroed(bcx, llty, name, zero);
137 // Subtle. Populate the scratch memory *before* scheduling cleanup.
138 let bcx = populate(arg, bcx, scratch);
139 bcx.fcx.schedule_drop_mem(scope, scratch, ty);
141 DatumBlock(bcx, Datum(scratch, ty, Lvalue))
144 pub fn rvalue_scratch_datum(bcx: &Block,
149 * Allocates temporary space on the stack using alloca() and
150 * returns a by-ref Datum pointing to it. If `zero` is true, the
151 * space will be zeroed when it is allocated; this is normally not
152 * necessary, but in the case of automatic rooting in match
153 * statements it is possible to have temporaries that may not get
154 * initialized if a certain arm is not taken, so we must zero
155 * them. You must arrange any cleanups etc yourself!
158 let llty = type_of::type_of(bcx.ccx(), ty);
159 let scratch = alloca_maybe_zeroed(bcx, llty, name, false);
160 Datum(scratch, ty, Rvalue(ByRef))
163 pub fn is_by_value_type(ccx: &CrateContext, ty: ty::t) -> bool {
164 appropriate_rvalue_mode(ccx, ty) == ByValue
167 pub fn appropriate_rvalue_mode(ccx: &CrateContext, ty: ty::t) -> RvalueMode {
169 * Indicates the "appropriate" mode for this value,
170 * which is either by ref or by value, depending
171 * on whether type is immediate or not.
174 if type_is_zero_size(ccx, ty) {
176 } else if type_is_immediate(ccx, ty) {
183 fn add_rvalue_clean(mode: RvalueMode,
184 fcx: &FunctionContext,
185 scope: cleanup::ScopeId,
189 ByValue => { fcx.schedule_drop_immediate(scope, val, ty); }
190 ByRef => { fcx.schedule_drop_mem(scope, val, ty); }
197 * Take appropriate action after the value in `datum` has been
198 * stored to a new location.
200 fn post_store<'a>(&self,
207 * True if this mode is a reference mode, meaning that the datum's
208 * val field is a pointer to the actual value
210 fn is_by_ref(&self) -> bool;
213 * Converts to an Expr kind
215 fn to_expr_kind(self) -> Expr;
219 impl KindOps for Rvalue {
220 fn post_store<'a>(&self,
225 // No cleanup is scheduled for an rvalue, so we don't have
226 // to do anything after a move to cancel or duplicate it.
230 fn is_by_ref(&self) -> bool {
234 fn to_expr_kind(self) -> Expr {
239 impl KindOps for Lvalue {
240 fn post_store<'a>(&self,
246 * If an lvalue is moved, we must zero out the memory in which
247 * it resides so as to cancel cleanup. If an @T lvalue is
248 * copied, we must increment the reference count.
251 if ty::type_needs_drop(bcx.tcx(), ty) {
252 if ty::type_moves_by_default(bcx.tcx(), ty) {
253 // cancel cleanup of affine values by zeroing out
254 let () = zero_mem(bcx, val, ty);
257 // incr. refcount for @T or newtype'd @T
258 glue::take_ty(bcx, val, ty)
265 fn is_by_ref(&self) -> bool {
269 fn to_expr_kind(self) -> Expr {
274 impl KindOps for Expr {
275 fn post_store<'a>(&self,
281 LvalueExpr => Lvalue.post_store(bcx, val, ty),
282 RvalueExpr(ref r) => r.post_store(bcx, val, ty),
286 fn is_by_ref(&self) -> bool {
288 LvalueExpr => Lvalue.is_by_ref(),
289 RvalueExpr(ref r) => r.is_by_ref()
293 fn to_expr_kind(self) -> Expr {
299 pub fn add_clean(self,
300 fcx: &FunctionContext,
301 scope: cleanup::ScopeId)
304 * Schedules a cleanup for this datum in the given scope.
305 * That means that this datum is no longer an rvalue datum;
306 * hence, this function consumes the datum and returns the
307 * contained ValueRef.
310 add_rvalue_clean(self.kind.mode, fcx, scope, self.val, self.ty);
314 pub fn to_lvalue_datum_in_scope<'a>(self,
317 scope: cleanup::ScopeId)
318 -> DatumBlock<'a, Lvalue> {
320 * Returns an lvalue datum (that is, a by ref datum with
321 * cleanup scheduled). If `self` is not already an lvalue,
322 * cleanup will be scheduled in the temporary scope for `expr_id`.
326 match self.kind.mode {
328 add_rvalue_clean(ByRef, fcx, scope, self.val, self.ty);
329 DatumBlock(bcx, Datum(self.val, self.ty, Lvalue))
333 lvalue_scratch_datum(
334 bcx, self.ty, name, false, scope, self,
335 |this, bcx, llval| this.store_to(bcx, llval))
340 pub fn to_ref_datum<'a>(self, bcx: &'a Block<'a>) -> DatumBlock<'a, Rvalue> {
342 match self.kind.mode {
343 ByRef => DatumBlock(bcx, self),
345 let scratch = rvalue_scratch_datum(bcx, self.ty, "to_ref");
346 bcx = self.store_to(bcx, scratch.val);
347 DatumBlock(bcx, scratch)
352 pub fn to_appropriate_datum<'a>(self,
354 -> DatumBlock<'a, Rvalue> {
355 match self.appropriate_rvalue_mode(bcx.ccx()) {
357 self.to_ref_datum(bcx)
360 match self.kind.mode {
361 ByValue => DatumBlock(bcx, self),
363 let llval = load(bcx, self.val, self.ty);
364 DatumBlock(bcx, Datum(llval, self.ty, Rvalue(ByValue)))
373 * Methods suitable for "expr" datums that could be either lvalues or
374 * rvalues. These include coercions into lvalues/rvalues but also a number
375 * of more general operations. (Some of those operations could be moved to
376 * the more general `impl<K> Datum<K>`, but it's convenient to have them
377 * here since we can `match self.kind` rather than having to implement
378 * generic methods in `KindOps`.)
381 fn match_kind<R>(self,
382 if_lvalue: |Datum<Lvalue>| -> R,
383 if_rvalue: |Datum<Rvalue>| -> R)
385 let Datum { val, ty, kind } = self;
387 LvalueExpr => if_lvalue(Datum(val, ty, Lvalue)),
388 RvalueExpr(r) => if_rvalue(Datum(val, ty, r)),
392 pub fn is_by_ref(&self) -> bool {
393 self.kind.is_by_ref()
396 pub fn assert_lvalue(self, bcx: &Block) -> Datum<Lvalue> {
398 * Asserts that this datum *is* an lvalue and returns it.
403 |_| bcx.sess().bug("assert_lvalue given rvalue"))
406 pub fn assert_rvalue(self, bcx: &Block) -> Datum<Rvalue> {
408 * Asserts that this datum *is* an lvalue and returns it.
412 |_| bcx.sess().bug("assert_rvalue given lvalue"),
416 pub fn store_to_dest<'a>(self,
419 expr_id: ast::NodeId)
423 self.add_clean_if_rvalue(bcx, expr_id);
426 expr::SaveIn(addr) => {
427 self.store_to(bcx, addr)
432 pub fn add_clean_if_rvalue<'a>(self,
434 expr_id: ast::NodeId) {
436 * Arranges cleanup for `self` if it is an rvalue. Use when
437 * you are done working with a value that may need drop.
441 |_| { /* Nothing to do, cleanup already arranged */ },
443 let scope = cleanup::temporary_scope(bcx.tcx(), expr_id);
444 r.add_clean(bcx.fcx, scope);
448 pub fn clean<'a>(self,
451 expr_id: ast::NodeId)
454 * Ensures that `self` will get cleaned up, if it is not an lvalue
458 self.to_lvalue_datum(bcx, name, expr_id).bcx
461 pub fn to_lvalue_datum<'a>(self,
464 expr_id: ast::NodeId)
465 -> DatumBlock<'a, Lvalue> {
467 |l| DatumBlock(bcx, l),
469 let scope = cleanup::temporary_scope(bcx.tcx(), expr_id);
470 r.to_lvalue_datum_in_scope(bcx, name, scope)
474 pub fn to_rvalue_datum<'a>(self,
477 -> DatumBlock<'a, Rvalue> {
479 * Ensures that we have an rvalue datum (that is, a datum with
480 * no cleanup scheduled).
486 match l.appropriate_rvalue_mode(bcx.ccx()) {
488 let scratch = rvalue_scratch_datum(bcx, l.ty, name);
489 bcx = l.store_to(bcx, scratch.val);
490 DatumBlock(bcx, scratch)
493 let v = load(bcx, l.val, l.ty);
494 bcx = l.kind.post_store(bcx, l.val, l.ty);
495 DatumBlock(bcx, Datum(v, l.ty, Rvalue(ByValue)))
499 |r| DatumBlock(bcx, r))
505 * Methods suitable only for lvalues. These include the various
506 * operations to extract components out of compound data structures,
507 * such as extracting the field from a struct or a particular element
511 pub fn to_llref(self) -> ValueRef {
513 * Converts a datum into a by-ref value. The datum type must
514 * be one which is always passed by reference.
520 pub fn get_element(&self,
522 gep: |ValueRef| -> ValueRef)
531 pub fn get_vec_base_and_len<'a>(&self, bcx: &'a Block<'a>) -> (ValueRef, ValueRef) {
532 //! Converts a vector into the slice pair.
534 tvec::get_base_and_len(bcx, self.val, self.ty)
538 fn load<'a>(bcx: &'a Block<'a>, llptr: ValueRef, ty: ty::t) -> ValueRef {
540 * Private helper for loading from a by-ref datum. Handles various
541 * special cases where the type gives us better information about
542 * what we are loading.
545 if type_is_zero_size(bcx.ccx(), ty) {
546 C_undef(type_of::type_of(bcx.ccx(), ty))
547 } else if ty::type_is_bool(ty) {
548 LoadRangeAssert(bcx, llptr, 0, 2, lib::llvm::False)
549 } else if ty::type_is_char(ty) {
550 // a char is a unicode codepoint, and so takes values from 0
551 // to 0x10FFFF inclusive only.
552 LoadRangeAssert(bcx, llptr, 0, 0x10FFFF + 1, lib::llvm::False)
559 * Generic methods applicable to any sort of datum.
561 impl<K:KindOps> Datum<K> {
562 pub fn to_expr_datum(self) -> Datum<Expr> {
563 let Datum { val, ty, kind } = self;
564 Datum { val: val, ty: ty, kind: kind.to_expr_kind() }
567 pub fn store_to<'a>(self,
572 * Moves or copies this value into a new home, as appropriate
573 * depending on the type of the datum. This method consumes
574 * the datum, since it would be incorrect to go on using the
575 * datum if the value represented is affine (and hence the value
579 self.shallow_copy(bcx, dst);
581 self.kind.post_store(bcx, self.val, self.ty)
584 fn shallow_copy<'a>(&self,
589 * Helper function that performs a shallow copy of this value
590 * into `dst`, which should be a pointer to a memory location
591 * suitable for `self.ty`. `dst` should contain uninitialized
592 * memory (either newly allocated, zeroed, or dropped).
594 * This function is private to datums because it leaves memory
595 * in an unstable state, where the source value has been
596 * copied but not zeroed. Public methods are `store_to` (if
597 * you no longer need the source value) or
598 * `shallow_copy_and_take` (if you wish the source value to
602 let _icx = push_ctxt("copy_to_no_check");
604 if type_is_zero_size(bcx.ccx(), self.ty) {
608 if self.kind.is_by_ref() {
609 memcpy_ty(bcx, dst, self.val, self.ty);
611 Store(bcx, self.val, dst);
617 pub fn shallow_copy_and_take<'a>(&self,
622 * Copies the value into a new location and runs any necessary
623 * take glue on the new location. This function always
624 * preserves the existing datum as a valid value. Therefore,
625 * it does not consume `self` and, also, cannot be applied to
626 * affine values (since they must never be duplicated).
629 assert!(!ty::type_moves_by_default(bcx.tcx(), self.ty));
631 bcx = self.shallow_copy(bcx, dst);
632 glue::take_ty(bcx, dst, self.ty)
635 pub fn to_str(&self, ccx: &CrateContext) -> ~str {
636 format!("Datum({}, {}, {:?})",
637 ccx.tn.val_to_str(self.val),
638 ty_to_str(ccx.tcx(), self.ty),
642 pub fn appropriate_rvalue_mode(&self, ccx: &CrateContext) -> RvalueMode {
643 /*! See the `appropriate_rvalue_mode()` function */
645 appropriate_rvalue_mode(ccx, self.ty)
648 pub fn root_and_write_guard<'a>(
652 expr_id: ast::NodeId,
655 write_guard::root_and_write_guard(self, bcx, span, expr_id, derefs)
658 pub fn to_llscalarish<'a>(self, bcx: &'a Block<'a>) -> ValueRef {
660 * Converts `self` into a by-value `ValueRef`. Consumes this
661 * datum (i.e., absolves you of responsibility to cleanup the
662 * value). For this to work, the value must be something
663 * scalar-ish (like an int or a pointer) which (1) does not
664 * require drop glue and (2) is naturally passed around by
665 * value, and not by reference.
668 assert!(!ty::type_needs_drop(bcx.tcx(), self.ty));
669 assert!(self.appropriate_rvalue_mode(bcx.ccx()) == ByValue);
670 if self.kind.is_by_ref() {
671 load(bcx, self.val, self.ty)
677 pub fn to_llbool<'a>(self, bcx: &'a Block<'a>) -> ValueRef {
678 assert!(ty::type_is_bool(self.ty) || ty::type_is_bot(self.ty))
679 let cond_val = self.to_llscalarish(bcx);
680 bool_to_i1(bcx, cond_val)
684 impl<'a, K:KindOps> DatumBlock<'a, K> {
685 pub fn to_expr_datumblock(self) -> DatumBlock<'a, Expr> {
686 DatumBlock(self.bcx, self.datum.to_expr_datum())
690 impl<'a> DatumBlock<'a, Expr> {
691 pub fn assert_by_ref(self) -> DatumBlock<'a, Expr> {
692 assert!(self.datum.kind.is_by_ref());
696 pub fn store_to(self, dst: ValueRef) -> &'a Block<'a> {
697 let DatumBlock { bcx, datum } = self;
698 datum.store_to(bcx, dst)
701 pub fn store_to_dest(self,
703 expr_id: ast::NodeId) -> &'a Block<'a> {
704 let DatumBlock { bcx, datum } = self;
705 datum.store_to_dest(bcx, dest, expr_id)
708 pub fn shallow_copy(self, dst: ValueRef) -> &'a Block<'a> {
709 self.datum.shallow_copy(self.bcx, dst)
712 pub fn ccx(&self) -> &'a CrateContext {
716 pub fn tcx(&self) -> &'a ty::ctxt {
720 pub fn to_str(&self) -> ~str {
721 self.datum.to_str(self.ccx())
724 pub fn to_llbool(self) -> Result<'a> {
725 let DatumBlock { datum, bcx } = self;
726 rslt(bcx, datum.to_llbool(bcx))