about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2013-04-22 16:22:36 -0700
committerPatrick Walton <pcwalton@mimiga.net>2013-04-29 14:30:53 -0700
commitb6277f8140a496bed371e97ea1e260858e77fb41 (patch)
treec85ae630368d3b5a1d0fb2b55ed585115b735c5a
parentb0522a497ccfcc7b124d77121d8f076af7f09b71 (diff)
downloadrust-b6277f8140a496bed371e97ea1e260858e77fb41.tar.gz
rust-b6277f8140a496bed371e97ea1e260858e77fb41.zip
librustc: Implement `reinterpret_cast` in terms of `transmute`.
-rw-r--r--src/libcore/cast.rs36
-rw-r--r--src/librustc/middle/trans/foreign.rs46
-rw-r--r--src/librustc/middle/trans/type_use.rs2
-rw-r--r--src/librustc/middle/typeck/check/mod.rs1
4 files changed, 84 insertions, 1 deletions
diff --git a/src/libcore/cast.rs b/src/libcore/cast.rs
index 1d214f402f5..620f716a63d 100644
--- a/src/libcore/cast.rs
+++ b/src/libcore/cast.rs
@@ -10,21 +10,48 @@
 
 //! Unsafe casting functions
 
+use sys;
+use unstable;
+
 pub mod rusti {
     #[abi = "rust-intrinsic"]
     #[link_name = "rusti"]
     pub extern "rust-intrinsic" {
         fn forget<T>(+x: T);
+
+        #[cfg(stage0)]
         fn reinterpret_cast<T, U>(&&e: T) -> U;
+
+        #[cfg(stage1)]
+        #[cfg(stage2)]
+        #[cfg(stage3)]
+        fn transmute<T,U>(e: T) -> U;
     }
 }
 
 /// Casts the value at `src` to U. The two types must have the same length.
 #[inline(always)]
+#[cfg(stage0)]
 pub unsafe fn reinterpret_cast<T, U>(src: &T) -> U {
     rusti::reinterpret_cast(*src)
 }
 
+#[inline(always)]
+#[cfg(stage1)]
+#[cfg(stage2)]
+#[cfg(stage3)]
+pub unsafe fn reinterpret_cast<T, U>(src: &T) -> U {
+    let mut dest: U = unstable::intrinsics::init();
+    {
+        let dest_ptr: *mut u8 = rusti::transmute(&mut dest);
+        let src_ptr: *u8 = rusti::transmute(src);
+        unstable::intrinsics::memmove64(dest_ptr,
+                                        src_ptr,
+                                        sys::size_of::<U>() as u64);
+    }
+    dest
+}
+
 /**
  * Move a thing into the void
  *
@@ -53,12 +80,21 @@ pub unsafe fn bump_box_refcount<T>(t: @T) { forget(t); }
  *     assert!(transmute("L") == ~[76u8, 0u8]);
  */
 #[inline(always)]
+#[cfg(stage0)]
 pub unsafe fn transmute<L, G>(thing: L) -> G {
     let newthing: G = reinterpret_cast(&thing);
     forget(thing);
     newthing
 }
 
+#[inline(always)]
+#[cfg(stage1)]
+#[cfg(stage2)]
+#[cfg(stage3)]
+pub unsafe fn transmute<L, G>(thing: L) -> G {
+    rusti::transmute(thing)
+}
+
 /// Coerce an immutable reference to be mutable.
 #[inline(always)]
 pub unsafe fn transmute_mut<'a,T>(ptr: &'a T) -> &'a mut T { transmute(ptr) }
diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs
index eab8f3c3d6c..64a157987bf 100644
--- a/src/librustc/middle/trans/foreign.rs
+++ b/src/librustc/middle/trans/foreign.rs
@@ -745,6 +745,52 @@ pub fn trans_intrinsic(ccx: @CrateContext,
               call_memcpy(bcx, llretptr, llcast, llsize_of(ccx, lltp_ty));
           }
         }
+        ~"transmute" => {
+            let (in_type, out_type) = (substs.tys[0], substs.tys[1]);
+            let llintype = type_of::type_of(ccx, in_type);
+            let llouttype = type_of::type_of(ccx, out_type);
+
+            let in_type_size = machine::llbitsize_of_real(ccx, llintype);
+            let out_type_size = machine::llbitsize_of_real(ccx, llouttype);
+            if in_type_size != out_type_size {
+                let sp = match *ccx.tcx.items.get(&ref_id.get()) {
+                    ast_map::node_expr(e) => e.span,
+                    _ => fail!(~"transmute has non-expr arg"),
+                };
+                let pluralize = |n| if 1u == n { "" } else { "s" };
+                ccx.sess.span_err(sp,
+                                  fmt!("transmute called on types with \
+                                        different sizes: %s (%u bit%s) to \
+                                        %s (%u bit%s)",
+                                       ty_to_str(ccx.tcx, in_type),
+                                       in_type_size,
+                                       pluralize(in_type_size),
+                                       ty_to_str(ccx.tcx, out_type),
+                                       out_type_size,
+                                       pluralize(out_type_size)));
+            }
+
+            if !ty::type_is_nil(out_type) {
+                // NB: Do not use a Load and Store here. This causes massive
+                // code bloat when `transmute` is used on large structural
+                // types.
+                let lldestptr = fcx.llretptr.get();
+                let lldestptr = PointerCast(bcx, lldestptr, T_ptr(T_i8()));
+
+                let llsrcval = get_param(decl, first_real_arg);
+                let llsrcptr = if ty::type_is_immediate(in_type) {
+                    let llsrcptr = alloca(bcx, llintype);
+                    Store(bcx, llsrcval, llsrcptr);
+                    llsrcptr
+                } else {
+                    llsrcval
+                };
+                let llsrcptr = PointerCast(bcx, llsrcptr, T_ptr(T_i8()));
+
+                let llsize = llsize_of(ccx, llintype);
+                call_memcpy(bcx, lldestptr, llsrcptr, llsize);
+            }
+        }
         ~"needs_drop" => {
             let tp_ty = substs.tys[0];
             Store(bcx,
diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs
index ea00f66448f..36e399cea80 100644
--- a/src/librustc/middle/trans/type_use.rs
+++ b/src/librustc/middle/trans/type_use.rs
@@ -123,7 +123,7 @@ pub fn type_uses_for(ccx: @CrateContext, fn_id: def_id, n_tps: uint)
         if abi.is_intrinsic() {
             let flags = match *cx.ccx.sess.str_of(i.ident) {
                 ~"size_of"  | ~"pref_align_of"    | ~"min_align_of" |
-                ~"init"     | ~"reinterpret_cast" |
+                ~"init"     | ~"reinterpret_cast" | ~"transmute"    |
                 ~"move_val" | ~"move_val_init" => use_repr,
 
                 ~"get_tydesc" | ~"needs_drop" => use_tydesc,
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index ea878d397d8..9b67f0b3e3f 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -3441,6 +3441,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) {
                     ty::mk_nil()),
       ~"reinterpret_cast" => (2u, ~[arg(ast::by_ref, param(ccx, 0u))],
                               param(ccx, 1u)),
+      ~"transmute" => (2, ~[arg(ast::by_copy, param(ccx, 0))], param(ccx, 1)),
       ~"move_val" | ~"move_val_init" => {
           (1u, ~[arg(ast::by_copy,
                      ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)),