From b6277f8140a496bed371e97ea1e260858e77fb41 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Mon, 22 Apr 2013 16:22:36 -0700 Subject: [PATCH] librustc: Implement `reinterpret_cast` in terms of `transmute`. --- src/libcore/cast.rs | 36 +++++++++++++++++++ src/librustc/middle/trans/foreign.rs | 46 +++++++++++++++++++++++++ src/librustc/middle/trans/type_use.rs | 2 +- src/librustc/middle/typeck/check/mod.rs | 1 + 4 files changed, 84 insertions(+), 1 deletion(-) diff --git a/src/libcore/cast.rs b/src/libcore/cast.rs index 1d214f402f5a..620f716a63d3 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(+x: T); + + #[cfg(stage0)] fn reinterpret_cast(&&e: T) -> U; + + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn transmute(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(src: &T) -> U { rusti::reinterpret_cast(*src) } +#[inline(always)] +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] +pub unsafe fn reinterpret_cast(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::() as u64); + } + dest +} + /** * Move a thing into the void * @@ -53,12 +80,21 @@ pub unsafe fn bump_box_refcount(t: @T) { forget(t); } * assert!(transmute("L") == ~[76u8, 0u8]); */ #[inline(always)] +#[cfg(stage0)] pub unsafe fn transmute(thing: L) -> G { let newthing: G = reinterpret_cast(&thing); forget(thing); newthing } +#[inline(always)] +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] +pub unsafe fn transmute(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 eab8f3c3d6cc..64a157987bf2 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 ea00f66448fa..36e399cea806 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 ea878d397d83..9b67f0b3e3f5 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)),