4

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?

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

1 Comment

+1 From my LLVM knowledge and what little I know about Rust's codegen strategy, your interpretation seems correct.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.