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.
13 * A `Datum` contains all the information you need to describe the LLVM
14 * translation of a Rust value. It describes where the value is stored,
15 * what Rust type the value has, whether it is addressed by reference,
18 * The idea of a datum is that, to the extent possible, you should not
19 * care about these details, but rather use the methods on the Datum
20 * type to "do what you want to do". For example, you can simply call
21 * `copy_to()` or `move_to()` to copy or move the value into a new
26 * The primary two fields of a datum are the `val` and the `mode`.
27 * The `val` is an LLVM value ref. It may either *be the value* that
28 * is being tracked, or it may be a *pointer to the value being
29 * tracked*. This is specified in the `mode` field, which can either
30 * be `ByValue` or `ByRef`, respectively. The (Rust) type of the
31 * value stored in the datum is indicated in the field `ty`.
33 * Generally speaking, you probably do not want to access the `val` field
34 * unless you know what mode the value is in. Instead you should use one
35 * of the following accessors:
37 * - `to_value_llval()` converts to by-value
38 * - `to_ref_llval()` converts to by-ref, allocating a stack slot if necessary
39 * - `to_appropriate_llval()` converts to by-value if this is an
40 * immediate type, by-ref otherwise. This is particularly
41 * convenient for interfacing with the various code floating around
42 * that predates datums.
44 * # Datum cleanup styles
46 * Each datum carries with it an idea of how its value will be cleaned
47 * up. This is primarily determined by the mode: a `ByValue` datum
48 * will always be cleaned up by revoking cleanup using
49 * `revoke_clean()`, because there is no other option. By ref datums
50 * can sometimes be cleaned up via `revoke_clean` (in particular,
51 * by-ref datums that originated from rvalues), but sometimes they
52 * must be zeroed. This is indicated by the `DatumCleanup`
53 * parameter. Note that zeroing a by-ref datum *always works* to
54 * cancel the cleanup, but using `revoke_clean` is preferable since
55 * there is no runtime cost. Some older parts of the code (notably
56 * `match_`, at least at the time of this writing) rely on this and
59 * # Copying, moving, and storing
61 * There are three methods for moving the value into a new
64 * - `copy_to()` will copy the value into a new location, meaning that
65 * the value is first mem-copied and then the new location is "taken"
66 * via the take glue, in effect creating a deep clone.
68 * - `move_to()` will copy the value, meaning that the value is mem-copied
69 * into its new home and then the cleanup on the this datum is revoked.
70 * This is a "shallow" clone. After `move_to()`, the current datum
71 * is invalid and should no longer be used.
73 * - `store_to()` either performs a copy or a move depending on the
74 * Rust type of the datum.
78 * Sometimes you just need some temporary scratch space. The
79 * `scratch_datum()` function will yield you up a by-ref datum that
80 * points into the stack. It's your responsibility to ensure that
81 * whatever you put in there gets cleaned up etc.
85 * There are various other helper methods on Datum, such as `deref()`,
86 * `get_base_and_len()` and so forth. These are documented on the
87 * methods themselves. Most are only suitable for some types of
92 use lib::llvm::ValueRef;
93 use middle::trans::adt;
94 use middle::trans::base::*;
95 use middle::trans::build::*;
96 use middle::trans::common::*;
97 use middle::trans::common;
98 use middle::trans::expr;
99 use middle::trans::glue;
100 use middle::trans::tvec;
101 use middle::trans::type_of;
102 use middle::trans::write_guard;
104 use util::common::indenter;
105 use util::ppaux::ty_to_str;
109 use syntax::codemap::Span;
110 use syntax::parse::token::special_idents;
113 pub enum CopyAction {
119 /// The llvm value. This is either a pointer to the Rust value or
120 /// the value itself, depending on `mode` below.
123 /// The rust type of the value.
126 /// Indicates whether this is by-ref or by-value.
130 pub struct DatumBlock {
135 #[deriving(Eq, IterBytes)]
137 /// `val` is a pointer to the actual value (and thus has type *T).
138 /// The argument indicates how to cancel cleanup of this datum if
139 /// the value is moved elsewhere, which can either be by zeroing
140 /// the memory or by canceling a registered cleanup.
143 /// `val` is the actual value (*only used for immediates* like ints, ptrs)
148 pub fn is_by_ref(&self) -> bool {
149 match *self { ByRef(_) => true, ByValue => false }
152 pub fn is_by_value(&self) -> bool {
153 match *self { ByRef(_) => false, ByValue => true }
157 /// See `Datum cleanup styles` section at the head of this module.
158 #[deriving(Eq, IterBytes)]
159 pub enum DatumCleanup {
164 pub fn immediate_rvalue(val: ValueRef, ty: ty::t) -> Datum {
165 return Datum {val: val, ty: ty, mode: ByValue};
168 pub fn immediate_rvalue_bcx(bcx: @mut Block,
172 return DatumBlock {bcx: bcx, datum: immediate_rvalue(val, ty)};
175 pub fn scratch_datum(bcx: @mut Block, ty: ty::t, name: &str, zero: bool) -> Datum {
177 * Allocates temporary space on the stack using alloca() and
178 * returns a by-ref Datum pointing to it. If `zero` is true, the
179 * space will be zeroed when it is allocated; this is normally not
180 * necessary, but in the case of automatic rooting in match
181 * statements it is possible to have temporaries that may not get
182 * initialized if a certain arm is not taken, so we must zero
183 * them. You must arrange any cleanups etc yourself!
186 let llty = type_of::type_of(bcx.ccx(), ty);
187 let scratch = alloca_maybe_zeroed(bcx, llty, name, zero);
188 Datum { val: scratch, ty: ty, mode: ByRef(RevokeClean) }
191 pub fn appropriate_mode(ccx: &mut CrateContext, ty: ty::t) -> DatumMode {
193 * Indicates the "appropriate" mode for this value,
194 * which is either by ref or by value, depending
195 * on whether type is immediate or not.
198 if ty::type_is_voidish(ccx.tcx, ty) {
200 } else if type_is_immediate(ccx, ty) {
208 pub fn store_to(&self,
215 * Stores this value into its final home. This moves if
216 * `id` is located in the move table, but copies otherwise.
219 if ty::type_moves_by_default(bcx.tcx(), self.ty) {
220 self.move_to(bcx, action, dst)
222 self.copy_to(bcx, action, dst)
226 pub fn store_to_dest(&self,
234 expr::SaveIn(addr) => {
235 return self.store_to(bcx, INIT, addr);
240 pub fn store_to_datum(&self,
245 debug2!("store_to_datum(self={}, action={:?}, datum={})",
246 self.to_str(bcx.ccx()), action, datum.to_str(bcx.ccx()));
247 assert!(datum.mode.is_by_ref());
248 self.store_to(bcx, action, datum.val)
251 pub fn move_to_datum(&self, bcx: @mut Block, action: CopyAction, datum: Datum)
253 assert!(datum.mode.is_by_ref());
254 self.move_to(bcx, action, datum.val)
257 pub fn copy_to_datum(&self, bcx: @mut Block, action: CopyAction, datum: Datum)
259 assert!(datum.mode.is_by_ref());
260 self.copy_to(bcx, action, datum.val)
263 pub fn copy_to(&self, bcx: @mut Block, action: CopyAction, dst: ValueRef)
267 * Copies the value into `dst`, which should be a pointer to a
268 * memory location suitable for `self.ty`. You PROBABLY want
269 * `store_to()` instead, which will move if possible but copy if
272 let _icx = push_ctxt("copy_to");
274 if ty::type_is_voidish(bcx.tcx(), self.ty) {
278 debug2!("copy_to(self={}, action={:?}, dst={})",
279 self.to_str(bcx.ccx()), action, bcx.val_to_str(dst));
281 // Watch out for the case where we are writing the copying the
282 // value into the same location we read it out from. We want
283 // to avoid the case where we drop the existing value, which
284 // frees it, and then overwrite it with itself (which has been
286 if action == DROP_EXISTING &&
287 ty::type_needs_drop(bcx.tcx(), self.ty)
291 let cast = PointerCast(bcx, dst, val_ty(self.val));
292 let cmp = ICmp(bcx, lib::llvm::IntNE, cast, self.val);
293 do with_cond(bcx, cmp) |bcx| {
294 self.copy_to_no_check(bcx, action, dst)
298 self.copy_to_no_check(bcx, action, dst)
302 self.copy_to_no_check(bcx, action, dst)
306 pub fn copy_to_no_check(&self,
313 * A helper for `copy_to()` which does not check to see if we
314 * are copying to/from the same value. */
316 let _icx = push_ctxt("copy_to_no_check");
319 if action == DROP_EXISTING {
320 bcx = glue::drop_ty(bcx, dst, self.ty);
325 Store(bcx, self.val, dst);
328 memcpy_ty(bcx, dst, self.val, self.ty);
332 return glue::take_ty(bcx, dst, self.ty);
335 // This works like copy_val, except that it deinitializes the source.
336 // Since it needs to zero out the source, src also needs to be an lval.
338 pub fn move_to(&self, bcx: @mut Block, action: CopyAction, dst: ValueRef)
340 let _icx = push_ctxt("move_to");
343 debug2!("move_to(self={}, action={:?}, dst={})",
344 self.to_str(bcx.ccx()), action, bcx.val_to_str(dst));
346 if ty::type_is_voidish(bcx.tcx(), self.ty) {
350 if action == DROP_EXISTING {
351 bcx = glue::drop_ty(bcx, dst, self.ty);
356 memcpy_ty(bcx, dst, self.val, self.ty);
359 Store(bcx, self.val, dst);
363 self.cancel_clean(bcx);
368 pub fn add_clean(&self, bcx: @mut Block) {
370 * Schedules this datum for cleanup in `bcx`. The datum
376 add_clean_temp_immediate(bcx, self.val, self.ty);
378 ByRef(RevokeClean) => {
379 add_clean_temp_mem(bcx, self.val, self.ty);
383 format!("Cannot add clean to a 'zero-mem' datum"));
388 pub fn cancel_clean(&self, bcx: @mut Block) {
389 if ty::type_needs_drop(bcx.tcx(), self.ty) {
392 ByRef(RevokeClean) => {
393 revoke_clean(bcx, self.val);
396 // Lvalues which potentially need to be dropped
397 // must be passed by ref, so that we can zero them
399 assert!(self.mode.is_by_ref());
400 zero_mem(bcx, self.val, self.ty);
406 pub fn to_str(&self, ccx: &CrateContext) -> ~str {
407 format!("Datum \\{ val={}, ty={}, mode={:?} \\}",
408 ccx.tn.val_to_str(self.val),
409 ty_to_str(ccx.tcx, self.ty),
413 pub fn to_value_datum(&self, bcx: @mut Block) -> Datum {
416 * Yields a by-value form of this datum. This may involve
417 * creation of a temporary stack slot. The value returned by
418 * this function is not separately rooted from this datum, so
419 * it will not live longer than the current datum. */
424 Datum {val: self.to_value_llval(bcx), mode: ByValue,
430 pub fn to_value_llval(&self, bcx: @mut Block) -> ValueRef {
433 * Yields the value itself. */
435 if ty::type_is_voidish(bcx.tcx(), self.ty) {
441 if ty::type_is_bool(self.ty) {
442 LoadRangeAssert(bcx, self.val, 0, 2, lib::llvm::True)
451 pub fn to_ref_datum(&self, bcx: @mut Block) -> Datum {
453 * Yields a by-ref form of this datum. This may involve
454 * creation of a temporary stack slot. The value returned by
455 * this function is not separately rooted from this datum, so
456 * it will not live longer than the current datum.
462 Datum {val: self.to_ref_llval(bcx), mode: ByRef(RevokeClean),
468 pub fn to_ref_llval(&self, bcx: @mut Block) -> ValueRef {
470 ByRef(_) => self.val,
472 if ty::type_is_voidish(bcx.tcx(), self.ty) {
473 C_null(type_of::type_of(bcx.ccx(), self.ty).ptr_to())
475 let slot = alloc_ty(bcx, self.ty, "");
476 Store(bcx, self.val, slot);
483 pub fn to_zeroable_ref_llval(&self, bcx: @mut Block) -> ValueRef {
485 * Returns a by-ref llvalue that can be zeroed in order to
486 * cancel cleanup. This is a kind of hokey bridge used
487 * to adapt to the match code. Please don't use it for new code.
491 // All by-ref datums are zeroable, even if we *could* just
492 // cancel the cleanup.
493 ByRef(_) => self.val,
495 // By value datums can't be zeroed (where would you store
496 // the zero?) so we have to spill them. Add a temp cleanup
497 // for this spilled value and cancel the cleanup on this
500 let slot = self.to_ref_llval(bcx);
501 self.cancel_clean(bcx);
502 add_clean_temp_mem(bcx, slot, self.ty);
508 pub fn appropriate_mode(&self, ccx: &mut CrateContext) -> DatumMode {
509 /*! See the `appropriate_mode()` function */
511 appropriate_mode(ccx, self.ty)
514 pub fn to_appropriate_llval(&self, bcx: @mut Block) -> ValueRef {
517 * Yields an llvalue with the `appropriate_mode()`. */
519 match self.appropriate_mode(bcx.ccx()) {
520 ByValue => self.to_value_llval(bcx),
521 ByRef(_) => self.to_ref_llval(bcx)
525 pub fn to_appropriate_datum(&self, bcx: @mut Block) -> Datum {
528 * Yields a datum with the `appropriate_mode()`. */
530 match self.appropriate_mode(bcx.ccx()) {
531 ByValue => self.to_value_datum(bcx),
532 ByRef(_) => self.to_ref_datum(bcx)
536 pub fn get_element(&self,
539 source: DatumCleanup,
540 gep: &fn(ValueRef) -> ValueRef)
542 let base_val = self.to_ref_llval(bcx);
550 pub fn drop_val(&self, bcx: @mut Block) -> @mut Block {
551 if !ty::type_needs_drop(bcx.tcx(), self.ty) {
555 return match self.mode {
556 ByRef(_) => glue::drop_ty(bcx, self.val, self.ty),
557 ByValue => glue::drop_ty_immediate(bcx, self.val, self.ty)
561 pub fn box_body(&self, bcx: @mut Block) -> Datum {
564 * This datum must represent an @T or ~T box. Returns a new
565 * by-ref datum of type T, pointing at the contents. */
567 let (content_ty, header) = match ty::get(self.ty).sty {
568 ty::ty_box(mt) => (mt.ty, true),
569 ty::ty_uniq(mt) => (mt.ty, false),
570 ty::ty_evec(_, ty::vstore_uniq) | ty::ty_estr(ty::vstore_uniq) => {
571 let unit_ty = ty::sequence_element_type(bcx.tcx(), self.ty);
572 let unboxed_vec_ty = ty::mk_mut_unboxed_vec(bcx.tcx(), unit_ty);
573 (unboxed_vec_ty, true)
576 bcx.tcx().sess.bug(format!(
577 "box_body() invoked on non-box type {}",
578 ty_to_str(bcx.tcx(), self.ty)));
582 if !header && !ty::type_contents(bcx.tcx(), content_ty).contains_managed() {
583 let ptr = self.to_value_llval(bcx);
584 let ty = type_of::type_of(bcx.ccx(), content_ty);
585 let body = PointerCast(bcx, ptr, ty.ptr_to());
586 Datum {val: body, ty: content_ty, mode: ByRef(ZeroMem)}
587 } else { // has a header
588 let ptr = self.to_value_llval(bcx);
589 let body = opaque_box_body(bcx, content_ty, ptr);
590 Datum {val: body, ty: content_ty, mode: ByRef(ZeroMem)}
594 pub fn to_rptr(&self, bcx: @mut Block) -> Datum {
595 //! Returns a new datum of region-pointer type containing the
596 //! the same ptr as this datum (after converting to by-ref
597 //! using `to_ref_llval()`).
599 // Convert to ref, yielding lltype *T. Then create a Rust
600 // type &'static T (which translates to *T). Construct new
601 // result (which will be by-value). Note that it is not
602 // significant *which* region we pick here.
603 let llval = self.to_ref_llval(bcx);
604 let rptr_ty = ty::mk_imm_rptr(bcx.tcx(), ty::re_static,
606 Datum {val: llval, ty: rptr_ty, mode: ByValue}
609 /// bcx: Block wherein to generate insns.
610 /// span: Location where deref occurs.
611 /// expr_id: ID of deref expr.
612 /// derefs: Number of times deref'd already.
613 /// is_auto: If true, only deref if auto-derefable.
614 pub fn try_deref(&self,
617 expr_id: ast::NodeId,
620 -> (Option<Datum>, @mut Block) {
623 debug2!("try_deref(expr_id={:?}, derefs={:?}, is_auto={}, self={:?})",
624 expr_id, derefs, is_auto, self.to_str(bcx.ccx()));
627 write_guard::root_and_write_guard(
628 self, bcx, span, expr_id, derefs);
630 match ty::get(self.ty).sty {
631 ty::ty_box(_) | ty::ty_uniq(_) => {
632 return (Some(self.box_body(bcx)), bcx);
635 if is_auto { // unsafe ptrs are not AUTO-derefable
638 return (Some(deref_ptr(bcx, self, mt.ty)), bcx);
641 ty::ty_rptr(_, mt) => {
642 return (Some(deref_ptr(bcx, self, mt.ty)), bcx);
644 ty::ty_enum(did, ref substs) => {
645 // Check whether this enum is a newtype enum:
646 let variants = ty::enum_variants(ccx.tcx, did);
647 if (*variants).len() != 1 || variants[0].args.len() != 1 {
651 let repr = adt::represent_type(ccx, self.ty);
652 let ty = ty::subst(ccx.tcx, substs, variants[0].args[0]);
653 return match self.mode {
655 // Recast lv.val as a pointer to the newtype
656 // rather than a ptr to the enum type.
659 val: adt::trans_field_ptr(bcx, repr, self.val,
668 // Actually, this case cannot happen right
669 // now, because enums are never immediate.
670 assert!(type_is_immediate(bcx.ccx(), ty));
671 (Some(Datum {ty: ty, ..*self}), bcx)
675 ty::ty_struct(did, ref substs) => {
676 // Check whether this struct is a newtype struct.
677 let fields = ty::struct_fields(ccx.tcx, did, substs);
678 if fields.len() != 1 || fields[0].ident !=
679 special_idents::unnamed_field {
683 let repr = adt::represent_type(ccx, self.ty);
684 let ty = fields[0].mt.ty;
685 return match self.mode {
687 // Recast lv.val as a pointer to the newtype rather
688 // than a pointer to the struct type.
689 // FIXME #6572: This isn't correct for structs with
693 val: adt::trans_field_ptr(bcx, repr, self.val,
702 assert!(type_is_immediate(bcx.ccx(), ty));
705 val: ExtractValue(bcx, self.val, 0),
714 _ => { // not derefable.
719 fn deref_ptr(bcx: @mut Block, lv: &Datum, ty: ty::t) -> Datum {
721 val: lv.to_value_llval(bcx),
728 /// expr: The deref expression.
729 pub fn deref(&self, bcx: @mut Block, expr: &ast::Expr, derefs: uint)
731 match self.try_deref(bcx, expr.span, expr.id, derefs, false) {
732 (Some(lvres), bcx) => DatumBlock { bcx: bcx, datum: lvres },
734 bcx.ccx().sess.span_bug(expr.span,
735 "Cannot deref this expression");
740 pub fn autoderef(&self,
743 expr_id: ast::NodeId,
746 let _icx = push_ctxt("autoderef");
748 debug2!("autoderef(expr_id={}, max={:?}, self={:?})",
749 expr_id, max, self.to_str(bcx.ccx()));
750 let _indenter = indenter();
752 let mut datum = *self;
757 match datum.try_deref(bcx, span, expr_id, derefs, true) {
758 (None, new_bcx) => { bcx = new_bcx; break }
759 (Some(datum_deref), new_bcx) => {
766 // either we were asked to deref a specific number of times,
767 // in which case we should have, or we asked to deref as many
769 assert!(derefs == max || max == uint::max_value);
770 DatumBlock { bcx: bcx, datum: datum }
773 pub fn get_vec_base_and_byte_len(&self,
776 expr_id: ast::NodeId,
778 -> (@mut Block, ValueRef, ValueRef) {
779 //! Converts a vector into the slice pair. Performs rooting
780 //! and write guards checks.
782 // only imp't for @[] and @str, but harmless
783 bcx = write_guard::root_and_write_guard(self, bcx, span, expr_id, derefs);
784 let (base, len) = self.get_vec_base_and_byte_len_no_root(bcx);
788 pub fn get_vec_base_and_byte_len_no_root(&self, bcx: @mut Block)
789 -> (ValueRef, ValueRef) {
790 //! Converts a vector into the slice pair. Des not root
791 //! nor perform write guard checks.
793 let llval = self.to_appropriate_llval(bcx);
794 tvec::get_base_and_byte_len(bcx, llval, self.ty)
797 pub fn get_vec_base_and_len(&self,
800 expr_id: ast::NodeId,
802 -> (@mut Block, ValueRef, ValueRef) {
803 //! Converts a vector into the slice pair. Performs rooting
804 //! and write guards checks.
806 // only imp't for @[] and @str, but harmless
807 bcx = write_guard::root_and_write_guard(self, bcx, span, expr_id, derefs);
808 let (base, len) = self.get_vec_base_and_len_no_root(bcx);
812 pub fn get_vec_base_and_len_no_root(&self, bcx: @mut Block)
813 -> (ValueRef, ValueRef) {
814 //! Converts a vector into the slice pair. Des not root
815 //! nor perform write guard checks.
817 let llval = self.to_appropriate_llval(bcx);
818 tvec::get_base_and_len(bcx, llval, self.ty)
821 pub fn root_and_write_guard(&self,
824 expr_id: ast::NodeId,
827 write_guard::root_and_write_guard(self, bcx, span, expr_id, derefs)
830 pub fn to_result(&self, bcx: @mut Block) -> common::Result {
831 rslt(bcx, self.to_appropriate_llval(bcx))
836 pub fn unpack(&self, bcx: &mut @mut Block) -> Datum {
841 pub fn assert_by_ref(&self) -> DatumBlock {
842 assert!(self.datum.mode.is_by_ref());
846 pub fn drop_val(&self) -> @mut Block {
847 self.datum.drop_val(self.bcx)
850 pub fn store_to(&self,
854 self.datum.store_to(self.bcx, action, dst)
857 pub fn copy_to(&self, action: CopyAction, dst: ValueRef) -> @mut Block {
858 self.datum.copy_to(self.bcx, action, dst)
861 pub fn move_to(&self, action: CopyAction, dst: ValueRef) -> @mut Block {
862 self.datum.move_to(self.bcx, action, dst)
865 pub fn to_value_llval(&self) -> ValueRef {
866 self.datum.to_value_llval(self.bcx)
869 pub fn to_result(&self) -> common::Result {
870 rslt(self.bcx, self.datum.to_appropriate_llval(self.bcx))
873 pub fn ccx(&self) -> @mut CrateContext {
877 pub fn tcx(&self) -> ty::ctxt {
881 pub fn to_str(&self) -> ~str {
882 self.datum.to_str(self.ccx())