1 // Copyright 2012-2014 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.
12 use back::{abi, link};
13 use llvm::{ValueRef, CallConv, get_param};
15 use middle::weak_lang_items;
16 use trans::attributes;
17 use trans::base::{llvm_linkage_by_name, push_ctxt};
22 use trans::debuginfo::DebugLoc;
26 use trans::monomorphize;
27 use trans::type_::Type;
28 use trans::type_of::*;
30 use middle::ty::{self, Ty};
31 use middle::subst::Substs;
36 use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi};
37 use syntax::abi::{PlatformIntrinsic, RustIntrinsic, Rust, RustCall, Stdcall, Fastcall, System};
39 use syntax::codemap::Span;
40 use syntax::parse::token::{InternedString, special_idents};
43 use rustc_front::print::pprust;
46 ///////////////////////////////////////////////////////////////////////////
49 struct ForeignTypes<'tcx> {
50 /// Rust signature of the function
51 fn_sig: ty::FnSig<'tcx>,
53 /// Adapter object for handling native ABI rules (trust me, you
54 /// don't want to know)
57 /// LLVM types that will appear on the foreign function
61 struct LlvmSignature {
62 // LLVM versions of the types of this function's arguments.
63 llarg_tys: Vec<Type> ,
65 // LLVM version of the type that this function returns. Note that
66 // this *may not be* the declared return type of the foreign
67 // function, because the foreign function may opt to return via an
71 /// True if there is a return value (not bottom, not unit)
76 ///////////////////////////////////////////////////////////////////////////
77 // Calls to external functions
79 pub fn llvm_calling_convention(ccx: &CrateContext,
80 abi: Abi) -> CallConv {
81 match ccx.sess().target.target.adjust_abi(abi) {
83 // Intrinsics are emitted at the call site
84 ccx.sess().bug("asked to register intrinsic fn");
86 PlatformIntrinsic => {
87 // Intrinsics are emitted at the call site
88 ccx.sess().bug("asked to register platform intrinsic fn");
92 // FIXME(#3678) Implement linking to foreign fns with Rust ABI
93 ccx.sess().unimpl("foreign functions with Rust ABI");
97 // FIXME(#3678) Implement linking to foreign fns with Rust ABI
98 ccx.sess().unimpl("foreign functions with RustCall ABI");
101 // It's the ABI's job to select this, not us.
102 System => ccx.sess().bug("system abi should be selected elsewhere"),
104 Stdcall => llvm::X86StdcallCallConv,
105 Fastcall => llvm::X86FastcallCallConv,
106 C => llvm::CCallConv,
107 Win64 => llvm::X86_64_Win64,
109 // These API constants ought to be more specific...
110 Cdecl => llvm::CCallConv,
111 Aapcs => llvm::CCallConv,
115 pub fn register_static(ccx: &CrateContext,
116 foreign_item: &hir::ForeignItem) -> ValueRef {
117 let ty = ccx.tcx().node_id_to_type(foreign_item.id);
118 let llty = type_of::type_of(ccx, ty);
120 let ident = link_name(foreign_item);
121 match attr::first_attr_value_str_by_name(&foreign_item.attrs,
123 // If this is a static with a linkage specified, then we need to handle
124 // it a little specially. The typesystem prevents things like &T and
125 // extern "C" fn() from being non-null, so we can't just declare a
126 // static and call it a day. Some linkages (like weak) will make it such
127 // that the static actually has a null value.
129 let linkage = match llvm_linkage_by_name(&name) {
130 Some(linkage) => linkage,
132 ccx.sess().span_fatal(foreign_item.span,
133 "invalid linkage specified");
136 let llty2 = match ty.sty {
137 ty::TyRawPtr(ref mt) => type_of::type_of(ccx, mt.ty),
139 ccx.sess().span_fatal(foreign_item.span,
140 "must have type `*T` or `*mut T`");
144 // Declare a symbol `foo` with the desired linkage.
145 let g1 = declare::declare_global(ccx, &ident[..], llty2);
146 llvm::SetLinkage(g1, linkage);
148 // Declare an internal global `extern_with_linkage_foo` which
149 // is initialized with the address of `foo`. If `foo` is
150 // discarded during linking (for example, if `foo` has weak
151 // linkage and there are no definitions), then
152 // `extern_with_linkage_foo` will instead be initialized to
154 let mut real_name = "_rust_extern_with_linkage_".to_string();
155 real_name.push_str(&ident);
156 let g2 = declare::define_global(ccx, &real_name[..], llty).unwrap_or_else(||{
157 ccx.sess().span_fatal(foreign_item.span,
158 &format!("symbol `{}` is already defined", ident))
160 llvm::SetLinkage(g2, llvm::InternalLinkage);
161 llvm::LLVMSetInitializer(g2, g1);
165 None => // Generate an external declaration.
166 declare::declare_global(ccx, &ident[..], llty),
170 // only use this for foreign function ABIs and glue, use `get_extern_rust_fn` for Rust functions
171 pub fn get_extern_fn(ccx: &CrateContext,
172 externs: &mut ExternMap,
178 match externs.get(name) {
179 Some(n) => return *n,
182 let f = declare::declare_fn(ccx, name, cc, ty, ty::FnConverging(output));
183 externs.insert(name.to_string(), f);
187 /// Registers a foreign function found in a library. Just adds a LLVM global.
188 pub fn register_foreign_item_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
189 abi: Abi, fty: Ty<'tcx>,
191 attrs: &[ast::Attribute])-> ValueRef {
192 debug!("register_foreign_item_fn(abi={:?}, \
199 let cc = llvm_calling_convention(ccx, abi);
201 // Register the function as a C extern fn
202 let tys = foreign_types_for_fn_ty(ccx, fty);
204 // Make sure the calling convention is right for variadic functions
205 // (should've been caught if not in typeck)
206 if tys.fn_sig.variadic {
207 assert!(cc == llvm::CCallConv);
210 // Create the LLVM value for the C extern fn
211 let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
213 let llfn = get_extern_fn(ccx, &mut *ccx.externs().borrow_mut(), name, cc, llfn_ty, fty);
214 attributes::unwind(llfn, false);
215 add_argument_attributes(&tys, llfn);
216 attributes::from_fn_attrs(ccx, attrs, llfn);
220 /// Prepares a call to a native function. This requires adapting
221 /// from the Rust argument passing rules to the native rules.
225 /// - `callee_ty`: Rust type for the function we are calling
226 /// - `llfn`: the function pointer we are calling
227 /// - `llretptr`: where to store the return value of the function
228 /// - `llargs_rust`: a list of the argument values, prepared
229 /// as they would be if calling a Rust function
230 /// - `passed_arg_tys`: Rust type for the arguments. Normally we
231 /// can derive these from callee_ty but in the case of variadic
232 /// functions passed_arg_tys will include the Rust type of all
233 /// the arguments including the ones not specified in the fn's signature.
234 pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
238 llargs_rust: &[ValueRef],
239 passed_arg_tys: Vec<Ty<'tcx>>,
240 call_debug_loc: DebugLoc)
245 debug!("trans_native_call(callee_ty={:?}, \
249 ccx.tn().val_to_string(llfn),
250 ccx.tn().val_to_string(llretptr));
252 let (fn_abi, fn_sig) = match callee_ty.sty {
253 ty::TyBareFn(_, ref fn_ty) => (fn_ty.abi, &fn_ty.sig),
254 _ => ccx.sess().bug("trans_native_call called on non-function type")
256 let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig);
257 let llsig = foreign_signature(ccx, &fn_sig, &passed_arg_tys[..]);
258 let fn_type = cabi::compute_abi_info(ccx,
263 let arg_tys: &[cabi::ArgType] = &fn_type.arg_tys;
265 let mut llargs_foreign = Vec::new();
267 // If the foreign ABI expects return value by pointer, supply the
268 // pointer that Rust gave us. Sometimes we have to bitcast
269 // because foreign fns return slightly different (but equivalent)
270 // views on the same type (e.g., i64 in place of {i32,i32}).
271 if fn_type.ret_ty.is_indirect() {
272 match fn_type.ret_ty.cast {
275 BitCast(bcx, llretptr, ty.ptr_to());
276 llargs_foreign.push(llcastedretptr);
279 llargs_foreign.push(llretptr);
285 for (i, arg_ty) in arg_tys.iter().enumerate() {
286 let mut llarg_rust = llargs_rust[i + offset];
288 if arg_ty.is_ignore() {
292 // Does Rust pass this argument by pointer?
293 let rust_indirect = type_of::arg_is_indirect(ccx, passed_arg_tys[i]);
295 debug!("argument {}, llarg_rust={}, rust_indirect={}, arg_ty={}",
297 ccx.tn().val_to_string(llarg_rust),
299 ccx.tn().type_to_string(arg_ty.ty));
301 // Ensure that we always have the Rust value indirectly,
302 // because it makes bitcasting easier.
304 let scratch = base::alloc_ty(bcx, passed_arg_tys[i], "__arg");
305 if type_is_fat_ptr(ccx.tcx(), passed_arg_tys[i]) {
306 Store(bcx, llargs_rust[i + offset], expr::get_dataptr(bcx, scratch));
307 Store(bcx, llargs_rust[i + offset + 1], expr::get_meta(bcx, scratch));
310 base::store_ty(bcx, llarg_rust, scratch, passed_arg_tys[i]);
312 llarg_rust = scratch;
315 debug!("llarg_rust={} (after indirection)",
316 ccx.tn().val_to_string(llarg_rust));
318 // Check whether we need to do any casting
320 Some(ty) => llarg_rust = BitCast(bcx, llarg_rust, ty.ptr_to()),
324 debug!("llarg_rust={} (after casting)",
325 ccx.tn().val_to_string(llarg_rust));
327 // Finally, load the value if needed for the foreign ABI
328 let foreign_indirect = arg_ty.is_indirect();
329 let llarg_foreign = if foreign_indirect {
332 if passed_arg_tys[i].is_bool() {
333 let val = LoadRangeAssert(bcx, llarg_rust, 0, 2, llvm::False);
334 Trunc(bcx, val, Type::i1(bcx.ccx()))
336 Load(bcx, llarg_rust)
340 debug!("argument {}, llarg_foreign={}",
341 i, ccx.tn().val_to_string(llarg_foreign));
343 // fill padding with undef value
345 Some(ty) => llargs_foreign.push(C_undef(ty)),
348 llargs_foreign.push(llarg_foreign);
351 let cc = llvm_calling_convention(ccx, fn_abi);
353 // A function pointer is called without the declaration available, so we have to apply
354 // any attributes with ABI implications directly to the call instruction.
355 let mut attrs = llvm::AttrBuilder::new();
357 // Add attributes that are always applicable, independent of the concrete foreign ABI
358 if fn_type.ret_ty.is_indirect() {
359 let llret_sz = machine::llsize_of_real(ccx, fn_type.ret_ty.ty);
361 // The outptr can be noalias and nocapture because it's entirely
362 // invisible to the program. We also know it's nonnull as well
363 // as how many bytes we can dereference
364 attrs.arg(1, llvm::Attribute::NoAlias)
365 .arg(1, llvm::Attribute::NoCapture)
366 .arg(1, llvm::DereferenceableAttribute(llret_sz));
369 // Add attributes that depend on the concrete foreign ABI
370 let mut arg_idx = if fn_type.ret_ty.is_indirect() { 1 } else { 0 };
371 match fn_type.ret_ty.attr {
372 Some(attr) => { attrs.arg(arg_idx, attr); },
377 for arg_ty in &fn_type.arg_tys {
378 if arg_ty.is_ignore() {
382 if arg_ty.pad.is_some() { arg_idx += 1; }
384 if let Some(attr) = arg_ty.attr {
385 attrs.arg(arg_idx, attr);
391 let llforeign_retval = CallWithConv(bcx,
398 // If the function we just called does not use an outpointer,
399 // store the result into the rust outpointer. Cast the outpointer
400 // type to match because some ABIs will use a different type than
401 // the Rust type. e.g., a {u32,u32} struct could be returned as
403 if llsig.ret_def && !fn_type.ret_ty.is_indirect() {
404 let llrust_ret_ty = llsig.llret_ty;
405 let llforeign_ret_ty = match fn_type.ret_ty.cast {
407 None => fn_type.ret_ty.ty
410 debug!("llretptr={}", ccx.tn().val_to_string(llretptr));
411 debug!("llforeign_retval={}", ccx.tn().val_to_string(llforeign_retval));
412 debug!("llrust_ret_ty={}", ccx.tn().type_to_string(llrust_ret_ty));
413 debug!("llforeign_ret_ty={}", ccx.tn().type_to_string(llforeign_ret_ty));
415 if llrust_ret_ty == llforeign_ret_ty {
416 match fn_sig.output {
417 ty::FnConverging(result_ty) => {
418 base::store_ty(bcx, llforeign_retval, llretptr, result_ty)
420 ty::FnDiverging => {}
423 // The actual return type is a struct, but the ABI
424 // adaptation code has cast it into some scalar type. The
425 // code that follows is the only reliable way I have
426 // found to do a transform like i64 -> {i32,i32}.
427 // Basically we dump the data onto the stack then memcpy it.
429 // Other approaches I tried:
430 // - Casting rust ret pointer to the foreign type and using Store
431 // is (a) unsafe if size of foreign type > size of rust type and
432 // (b) runs afoul of strict aliasing rules, yielding invalid
433 // assembly under -O (specifically, the store gets removed).
434 // - Truncating foreign type to correct integral type and then
435 // bitcasting to the struct type yields invalid cast errors.
436 let llscratch = base::alloca(bcx, llforeign_ret_ty, "__cast");
437 base::call_lifetime_start(bcx, llscratch);
438 Store(bcx, llforeign_retval, llscratch);
439 let llscratch_i8 = BitCast(bcx, llscratch, Type::i8(ccx).ptr_to());
440 let llretptr_i8 = BitCast(bcx, llretptr, Type::i8(ccx).ptr_to());
441 let llrust_size = machine::llsize_of_store(ccx, llrust_ret_ty);
442 let llforeign_align = machine::llalign_of_min(ccx, llforeign_ret_ty);
443 let llrust_align = machine::llalign_of_min(ccx, llrust_ret_ty);
444 let llalign = cmp::min(llforeign_align, llrust_align);
445 debug!("llrust_size={}", llrust_size);
446 base::call_memcpy(bcx, llretptr_i8, llscratch_i8,
447 C_uint(ccx, llrust_size), llalign as u32);
448 base::call_lifetime_end(bcx, llscratch);
455 // feature gate SIMD types in FFI, since I (huonw) am not sure the
456 // ABIs are handled at all correctly.
457 fn gate_simd_ffi(tcx: &ty::ctxt, decl: &hir::FnDecl, ty: &ty::BareFnTy) {
458 if !tcx.sess.features.borrow().simd_ffi {
459 let check = |ast_ty: &hir::Ty, ty: ty::Ty| {
461 tcx.sess.span_err(ast_ty.span,
462 &format!("use of SIMD type `{}` in FFI is highly experimental and \
463 may result in invalid code",
464 pprust::ty_to_string(ast_ty)));
465 tcx.sess.fileline_help(ast_ty.span,
466 "add #![feature(simd_ffi)] to the crate attributes to enable");
470 for (input, ty) in decl.inputs.iter().zip(&sig.inputs) {
471 check(&*input.ty, *ty)
473 if let hir::Return(ref ty) = decl.output {
474 check(&**ty, sig.output.unwrap())
479 pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &hir::ForeignMod) {
480 let _icx = push_ctxt("foreign::trans_foreign_mod");
481 for foreign_item in &foreign_mod.items {
482 let lname = link_name(&**foreign_item);
484 if let hir::ForeignItemFn(ref decl, _) = foreign_item.node {
485 match foreign_mod.abi {
486 Rust | RustIntrinsic | PlatformIntrinsic => {}
488 let ty = ccx.tcx().node_id_to_type(foreign_item.id);
490 ty::TyBareFn(_, bft) => gate_simd_ffi(ccx.tcx(), &**decl, bft),
491 _ => ccx.tcx().sess.span_bug(foreign_item.span,
492 "foreign fn's sty isn't a bare_fn_ty?")
495 register_foreign_item_fn(ccx, abi, ty, &lname, &foreign_item.attrs);
496 // Unlike for other items, we shouldn't call
497 // `base::update_linkage` here. Foreign items have
498 // special linkage requirements, which are handled
499 // inside `foreign::register_*`.
504 ccx.item_symbols().borrow_mut().insert(foreign_item.id,
509 ///////////////////////////////////////////////////////////////////////////
510 // Rust functions with foreign ABIs
512 // These are normal Rust functions defined with foreign ABIs. For
513 // now, and perhaps forever, we translate these using a "layer of
514 // indirection". That is, given a Rust declaration like:
516 // extern "C" fn foo(i: u32) -> u32 { ... }
518 // we will generate a function like:
522 // foo0(&r, NULL, i);
527 // void foo0(uint32_t *r, void *env, uint32_t i) { ... }
529 // Here the (internal) `foo0` function follows the Rust ABI as normal,
530 // where the `foo` function follows the C ABI. We rely on LLVM to
531 // inline the one into the other. Of course we could just generate the
532 // correct code in the first place, but this is much simpler.
534 pub fn decl_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
538 let tys = foreign_types_for_fn_ty(ccx, t);
539 let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
540 let cconv = match t.sty {
541 ty::TyBareFn(_, ref fn_ty) => {
542 llvm_calling_convention(ccx, fn_ty.abi)
544 _ => panic!("expected bare fn in decl_rust_fn_with_foreign_abi")
546 let llfn = declare::declare_fn(ccx, name, cconv, llfn_ty,
547 ty::FnConverging(ccx.tcx().mk_nil()));
548 add_argument_attributes(&tys, llfn);
549 debug!("decl_rust_fn_with_foreign_abi(llfn_ty={}, llfn={})",
550 ccx.tn().type_to_string(llfn_ty), ccx.tn().val_to_string(llfn));
554 pub fn register_rust_fn_with_foreign_abi(ccx: &CrateContext,
557 node_id: ast::NodeId)
559 let _icx = push_ctxt("foreign::register_foreign_fn");
561 let tys = foreign_types_for_id(ccx, node_id);
562 let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
563 let t = ccx.tcx().node_id_to_type(node_id);
564 let cconv = match t.sty {
565 ty::TyBareFn(_, ref fn_ty) => {
566 llvm_calling_convention(ccx, fn_ty.abi)
568 _ => panic!("expected bare fn in register_rust_fn_with_foreign_abi")
570 let llfn = base::register_fn_llvmty(ccx, sp, sym, node_id, cconv, llfn_ty);
571 add_argument_attributes(&tys, llfn);
572 debug!("register_rust_fn_with_foreign_abi(node_id={}, llfn_ty={}, llfn={})",
573 node_id, ccx.tn().type_to_string(llfn_ty), ccx.tn().val_to_string(llfn));
577 pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
580 attrs: &[ast::Attribute],
582 param_substs: &'tcx Substs<'tcx>,
584 hash: Option<&str>) {
585 let _icx = push_ctxt("foreign::build_foreign_fn");
587 let fnty = ccx.tcx().node_id_to_type(id);
588 let mty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &fnty);
589 let tys = foreign_types_for_fn_ty(ccx, mty);
591 unsafe { // unsafe because we call LLVM operations
592 // Build up the Rust function (`foo0` above).
593 let llrustfn = build_rust_fn(ccx, decl, body, param_substs, attrs, id, hash);
595 // Build up the foreign wrapper (`foo` above).
596 return build_wrap_fn(ccx, llrustfn, llwrapfn, &tys, mty);
599 fn build_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
602 param_substs: &'tcx Substs<'tcx>,
603 attrs: &[ast::Attribute],
608 let _icx = push_ctxt("foreign::foreign::build_rust_fn");
610 let t = tcx.node_id_to_type(id);
611 let t = monomorphize::apply_param_substs(tcx, param_substs, &t);
614 tcx.map.def_path_from_id(id)
616 .map(|e| e.data.as_interned_str())
617 .chain(once(special_idents::clownshoe_abi.name.as_str()));
618 let ps = link::mangle(path, hash);
620 // Compute the type that the function would have if it were just a
621 // normal Rust function. This will be the type of the wrappee fn.
623 ty::TyBareFn(_, ref f) => {
624 assert!(f.abi != Rust && f.abi != RustIntrinsic && f.abi != PlatformIntrinsic);
627 ccx.sess().bug(&format!("build_rust_fn: extern fn {} has ty {:?}, \
628 expected a bare fn ty",
629 ccx.tcx().map.path_to_string(id),
634 debug!("build_rust_fn: path={} id={} t={:?}",
635 ccx.tcx().map.path_to_string(id),
638 let llfn = declare::define_internal_rust_fn(ccx, &ps, t);
639 attributes::from_fn_attrs(ccx, attrs, llfn);
640 base::trans_fn(ccx, decl, body, llfn, param_substs, id, &[]);
644 unsafe fn build_wrap_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
647 tys: &ForeignTypes<'tcx>,
649 let _icx = push_ctxt(
650 "foreign::trans_rust_fn_with_foreign_abi::build_wrap_fn");
652 debug!("build_wrap_fn(llrustfn={}, llwrapfn={}, t={:?})",
653 ccx.tn().val_to_string(llrustfn),
654 ccx.tn().val_to_string(llwrapfn),
657 // Avoid all the Rust generation stuff and just generate raw
660 // We want to generate code like this:
664 // foo0(&r, NULL, i);
668 if llvm::LLVMCountBasicBlocks(llwrapfn) != 0 {
669 ccx.sess().bug("wrapping a function inside non-empty wrapper, most likely cause is \
670 multiple functions being wrapped");
673 let ptr = "the block\0".as_ptr();
674 let the_block = llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llwrapfn,
677 let builder = ccx.builder();
678 builder.position_at_end(the_block);
680 // Array for the arguments we will pass to the rust function.
681 let mut llrust_args = Vec::new();
682 let mut next_foreign_arg_counter: c_uint = 0;
683 let mut next_foreign_arg = |pad: bool| -> c_uint {
684 next_foreign_arg_counter += if pad {
689 next_foreign_arg_counter - 1
692 // If there is an out pointer on the foreign function
693 let foreign_outptr = {
694 if tys.fn_ty.ret_ty.is_indirect() {
695 Some(get_param(llwrapfn, next_foreign_arg(false)))
701 let rustfn_ty = Type::from_ref(llvm::LLVMTypeOf(llrustfn)).element_type();
702 let mut rust_param_tys = rustfn_ty.func_params().into_iter();
703 // Push Rust return pointer, using null if it will be unused.
704 let rust_uses_outptr = match tys.fn_sig.output {
705 ty::FnConverging(ret_ty) => type_of::return_uses_outptr(ccx, ret_ty),
706 ty::FnDiverging => false
708 let return_alloca: Option<ValueRef>;
709 let llrust_ret_ty = if rust_uses_outptr {
710 rust_param_tys.next().expect("Missing return type!").element_type()
712 rustfn_ty.return_type()
714 if rust_uses_outptr {
715 // Rust expects to use an outpointer. If the foreign fn
716 // also uses an outpointer, we can reuse it, but the types
717 // may vary, so cast first to the Rust type. If the
718 // foreign fn does NOT use an outpointer, we will have to
719 // alloca some scratch space on the stack.
720 match foreign_outptr {
721 Some(llforeign_outptr) => {
722 debug!("out pointer, foreign={}",
723 ccx.tn().val_to_string(llforeign_outptr));
725 builder.bitcast(llforeign_outptr, llrust_ret_ty.ptr_to());
726 debug!("out pointer, foreign={} (casted)",
727 ccx.tn().val_to_string(llrust_retptr));
728 llrust_args.push(llrust_retptr);
729 return_alloca = None;
733 let slot = builder.alloca(llrust_ret_ty, "return_alloca");
734 debug!("out pointer, \
738 ccx.tn().val_to_string(slot),
739 ccx.tn().type_to_string(llrust_ret_ty),
741 llrust_args.push(slot);
742 return_alloca = Some(slot);
746 // Rust does not expect an outpointer. If the foreign fn
747 // does use an outpointer, then we will do a store of the
748 // value that the Rust fn returns.
749 return_alloca = None;
752 // Build up the arguments to the call to the rust function.
753 // Careful to adapt for cases where the native convention uses
754 // a pointer and Rust does not or vice versa.
755 for i in 0..tys.fn_sig.inputs.len() {
756 let rust_ty = tys.fn_sig.inputs[i];
757 let rust_indirect = type_of::arg_is_indirect(ccx, rust_ty);
758 let llty = rust_param_tys.next().expect("Not enough parameter types!");
759 let llrust_ty = if rust_indirect {
764 let llforeign_arg_ty = tys.fn_ty.arg_tys[i];
765 let foreign_indirect = llforeign_arg_ty.is_indirect();
767 if llforeign_arg_ty.is_ignore() {
768 debug!("skipping ignored arg #{}", i);
769 llrust_args.push(C_undef(llrust_ty));
774 let foreign_index = next_foreign_arg(llforeign_arg_ty.pad.is_some());
775 let mut llforeign_arg = get_param(llwrapfn, foreign_index);
777 debug!("llforeign_arg {}{}: {}", "#",
778 i, ccx.tn().val_to_string(llforeign_arg));
779 debug!("rust_indirect = {}, foreign_indirect = {}",
780 rust_indirect, foreign_indirect);
782 // Ensure that the foreign argument is indirect (by
783 // pointer). It makes adapting types easier, since we can
784 // always just bitcast pointers.
785 if !foreign_indirect {
786 llforeign_arg = if rust_ty.is_bool() {
787 let lltemp = builder.alloca(Type::bool(ccx), "");
788 builder.store(builder.zext(llforeign_arg, Type::bool(ccx)), lltemp);
791 let lltemp = builder.alloca(val_ty(llforeign_arg), "");
792 builder.store(llforeign_arg, lltemp);
797 // If the types in the ABI and the Rust types don't match,
798 // bitcast the llforeign_arg pointer so it matches the types
800 if llforeign_arg_ty.cast.is_some() && !type_is_fat_ptr(ccx.tcx(), rust_ty){
801 assert!(!foreign_indirect);
802 llforeign_arg = builder.bitcast(llforeign_arg, llrust_ty.ptr_to());
805 let llrust_arg = if rust_indirect || type_is_fat_ptr(ccx.tcx(), rust_ty) {
808 if rust_ty.is_bool() {
809 let tmp = builder.load_range_assert(llforeign_arg, 0, 2, llvm::False);
810 builder.trunc(tmp, Type::i1(ccx))
811 } else if type_of::type_of(ccx, rust_ty).is_aggregate() {
812 // We want to pass small aggregates as immediate values, but using an aggregate
813 // LLVM type for this leads to bad optimizations, so its arg type is an
814 // appropriately sized integer and we have to convert it
815 let tmp = builder.bitcast(llforeign_arg,
816 type_of::arg_type_of(ccx, rust_ty).ptr_to());
817 let load = builder.load(tmp);
818 llvm::LLVMSetAlignment(load, type_of::align_of(ccx, rust_ty));
821 builder.load(llforeign_arg)
825 debug!("llrust_arg {}{}: {}", "#",
826 i, ccx.tn().val_to_string(llrust_arg));
827 if type_is_fat_ptr(ccx.tcx(), rust_ty) {
828 let next_llrust_ty = rust_param_tys.next().expect("Not enough parameter types!");
829 llrust_args.push(builder.load(builder.bitcast(builder.struct_gep(
830 llrust_arg, abi::FAT_PTR_ADDR), llrust_ty.ptr_to())));
831 llrust_args.push(builder.load(builder.bitcast(builder.struct_gep(
832 llrust_arg, abi::FAT_PTR_EXTRA), next_llrust_ty.ptr_to())));
834 llrust_args.push(llrust_arg);
838 // Perform the call itself
839 debug!("calling llrustfn = {}, t = {:?}",
840 ccx.tn().val_to_string(llrustfn), t);
841 let attributes = attributes::from_fn_type(ccx, t);
842 let llrust_ret_val = builder.call(llrustfn, &llrust_args, Some(attributes));
844 // Get the return value where the foreign fn expects it.
845 let llforeign_ret_ty = match tys.fn_ty.ret_ty.cast {
847 None => tys.fn_ty.ret_ty.ty
849 match foreign_outptr {
850 None if !tys.llsig.ret_def => {
851 // Function returns `()` or `bot`, which in Rust is the LLVM
852 // type "{}" but in foreign ABIs is "Void".
856 None if rust_uses_outptr => {
857 // Rust uses an outpointer, but the foreign ABI does not. Load.
858 let llrust_outptr = return_alloca.unwrap();
859 let llforeign_outptr_casted =
860 builder.bitcast(llrust_outptr, llforeign_ret_ty.ptr_to());
861 let llforeign_retval = builder.load(llforeign_outptr_casted);
862 builder.ret(llforeign_retval);
865 None if llforeign_ret_ty != llrust_ret_ty => {
866 // Neither ABI uses an outpointer, but the types don't
867 // quite match. Must cast. Probably we should try and
868 // examine the types and use a concrete llvm cast, but
869 // right now we just use a temp memory location and
870 // bitcast the pointer, which is the same thing the
871 // old wrappers used to do.
872 let lltemp = builder.alloca(llforeign_ret_ty, "");
873 let lltemp_casted = builder.bitcast(lltemp, llrust_ret_ty.ptr_to());
874 builder.store(llrust_ret_val, lltemp_casted);
875 let llforeign_retval = builder.load(lltemp);
876 builder.ret(llforeign_retval);
880 // Neither ABI uses an outpointer, and the types
881 // match. Easy peasy.
882 builder.ret(llrust_ret_val);
885 Some(llforeign_outptr) if !rust_uses_outptr => {
886 // Foreign ABI requires an out pointer, but Rust doesn't.
887 // Store Rust return value.
888 let llforeign_outptr_casted =
889 builder.bitcast(llforeign_outptr, llrust_ret_ty.ptr_to());
890 builder.store(llrust_ret_val, llforeign_outptr_casted);
895 // Both ABIs use outpointers. Easy peasy.
902 ///////////////////////////////////////////////////////////////////////////
903 // General ABI Support
905 // This code is kind of a confused mess and needs to be reworked given
906 // the massive simplifications that have occurred.
908 pub fn link_name(i: &hir::ForeignItem) -> InternedString {
909 match attr::first_attr_value_str_by_name(&i.attrs, "link_name") {
910 Some(ln) => ln.clone(),
911 None => match weak_lang_items::link_name(&i.attrs) {
913 None => i.name.as_str(),
918 /// The ForeignSignature is the LLVM types of the arguments/return type of a function. Note that
919 /// these LLVM types are not quite the same as the LLVM types would be for a native Rust function
920 /// because foreign functions just plain ignore modes. They also don't pass aggregate values by
921 /// pointer like we do.
922 fn foreign_signature<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
923 fn_sig: &ty::FnSig<'tcx>,
924 arg_tys: &[Ty<'tcx>])
926 let llarg_tys = arg_tys.iter().map(|&arg| foreign_arg_type_of(ccx, arg)).collect();
927 let (llret_ty, ret_def) = match fn_sig.output {
928 ty::FnConverging(ret_ty) =>
929 (type_of::foreign_arg_type_of(ccx, ret_ty), !return_type_is_void(ccx, ret_ty)),
931 (Type::nil(ccx), false)
934 llarg_tys: llarg_tys,
940 fn foreign_types_for_id<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
941 id: ast::NodeId) -> ForeignTypes<'tcx> {
942 foreign_types_for_fn_ty(ccx, ccx.tcx().node_id_to_type(id))
945 fn foreign_types_for_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
946 ty: Ty<'tcx>) -> ForeignTypes<'tcx> {
947 let fn_sig = match ty.sty {
948 ty::TyBareFn(_, ref fn_ty) => &fn_ty.sig,
949 _ => ccx.sess().bug("foreign_types_for_fn_ty called on non-function type")
951 let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig);
952 let llsig = foreign_signature(ccx, &fn_sig, &fn_sig.inputs);
953 let fn_ty = cabi::compute_abi_info(ccx,
957 debug!("foreign_types_for_fn_ty(\
963 ccx.tn().types_to_str(&llsig.llarg_tys),
964 ccx.tn().type_to_string(llsig.llret_ty),
965 ccx.tn().types_to_str(&fn_ty.arg_tys.iter().map(|t| t.ty).collect::<Vec<_>>()),
966 ccx.tn().type_to_string(fn_ty.ret_ty.ty),
976 fn lltype_for_fn_from_foreign_types(ccx: &CrateContext, tys: &ForeignTypes) -> Type {
977 let mut llargument_tys = Vec::new();
979 let ret_ty = tys.fn_ty.ret_ty;
980 let llreturn_ty = if ret_ty.is_indirect() {
981 llargument_tys.push(ret_ty.ty.ptr_to());
990 for &arg_ty in &tys.fn_ty.arg_tys {
991 if arg_ty.is_ignore() {
996 Some(ty) => llargument_tys.push(ty),
1000 let llarg_ty = if arg_ty.is_indirect() {
1009 llargument_tys.push(llarg_ty);
1012 if tys.fn_sig.variadic {
1013 Type::variadic_func(&llargument_tys, &llreturn_ty)
1015 Type::func(&llargument_tys[..], &llreturn_ty)
1019 pub fn lltype_for_foreign_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
1020 ty: Ty<'tcx>) -> Type {
1021 lltype_for_fn_from_foreign_types(ccx, &foreign_types_for_fn_ty(ccx, ty))
1024 fn add_argument_attributes(tys: &ForeignTypes,
1026 let mut i = if tys.fn_ty.ret_ty.is_indirect() {
1032 match tys.fn_ty.ret_ty.attr {
1033 Some(attr) => unsafe {
1034 llvm::LLVMAddFunctionAttribute(llfn, i as c_uint, attr.bits() as u64);
1041 for &arg_ty in &tys.fn_ty.arg_tys {
1042 if arg_ty.is_ignore() {
1046 if arg_ty.pad.is_some() { i += 1; }
1049 Some(attr) => unsafe {
1050 llvm::LLVMAddFunctionAttribute(llfn, i as c_uint, attr.bits() as u64);