Question

I'm trying to find the implementation for the Rust intrinsics, particularly the "transumte" intrinsic that takes one argument.

I've seen the following code in cast.rs, but as you can see, it merely delegates to some other implementation of transmute.

#[inline]
pub unsafe fn transmute<L, G>(thing: L) -> G {
    intrinsics::transmute(thing)
}

Where is the actual implementation for intrinsics, especially the transmute intrinsic?

Was it helpful?

Solution

cast::transmute delegates to intrinsics::transmute. There is a module called intrinsics (now in libcore), it contains extern bindings to several functions, including transmute. As you can see from the module documentation, implementation of intrinsics is said to be located in librustc/middle/trans/foreign.rs.

However, as far as I can see, actual implementation of intrinsics is present in librustc/middle/trans/intrinsic.rs. You can search for transmute, and you will find an arm in a really big match statement which looks like this:

    "transmute" => {
        let (in_type, out_type) = (*substs.substs.tps.get(0),
                                   *substs.substs.tps.get(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.map.get(ref_id.unwrap()) {
                ast_map::NodeExpr(e) => e.span,
                _ => fail!("transmute has non-expr arg"),
            };
            ccx.sess().span_fatal(sp,
                format!("transmute called on types with different sizes: \
                         {intype} ({insize, plural, =1{# bit} other{# bits}}) to \
                         {outtype} ({outsize, plural, =1{# bit} other{# bits}})",
                        intype = ty_to_str(ccx.tcx(), in_type),
                        insize = in_type_size as uint,
                        outtype = ty_to_str(ccx.tcx(), out_type),
                        outsize = out_type_size as uint));
        }

        if !return_type_is_void(ccx, out_type) {
            let llsrcval = get_param(decl, first_real_arg);
            if type_is_immediate(ccx, in_type) {
                match fcx.llretptr.get() {
                    Some(llretptr) => {
                        Store(bcx, llsrcval, PointerCast(bcx, llretptr, llintype.ptr_to()));
                        RetVoid(bcx);
                    }
                    None => match (llintype.kind(), llouttype.kind()) {
                        (Pointer, other) | (other, Pointer) if other != Pointer => {
                            let tmp = Alloca(bcx, llouttype, "");
                            Store(bcx, llsrcval, PointerCast(bcx, tmp, llintype.ptr_to()));
                            Ret(bcx, Load(bcx, tmp));
                        }
                        (Array, _) | (_, Array) | (Struct, _) | (_, Struct) => {
                            let tmp = Alloca(bcx, llouttype, "");
                            Store(bcx, llsrcval, PointerCast(bcx, tmp, llintype.ptr_to()));
                            Ret(bcx, Load(bcx, tmp));
                        }
                        _ => {
                            let llbitcast = BitCast(bcx, llsrcval, llouttype);
                            Ret(bcx, llbitcast)
                        }
                    }
                }
            } else if type_is_immediate(ccx, out_type) {
                let llsrcptr = PointerCast(bcx, llsrcval, llouttype.ptr_to());
                let ll_load = Load(bcx, llsrcptr);
                Ret(bcx, ll_load);
            } else {
                // 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().unwrap();
                let lldestptr = PointerCast(bcx, lldestptr, Type::i8p(ccx));
                let llsrcptr = PointerCast(bcx, llsrcval, Type::i8p(ccx));

                let llsize = llsize_of(ccx, llintype);
                call_memcpy(bcx, lldestptr, llsrcptr, llsize, 1);
                RetVoid(bcx);
            };
        } else {
            RetVoid(bcx);
        }
    }

This seems to be code which generates code which will be inserted instead of a call to transmute. I'm no compiler expert, so please someone correct me if I'm wrong.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top