1 // Copyright 2012-2013 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.
14 use lib::llvm::{ValueRef, CallConv, StructRetAttribute, Linkage};
16 use middle::trans::base::push_ctxt;
17 use middle::trans::base;
18 use middle::trans::build::*;
19 use middle::trans::builder::noname;
20 use middle::trans::cabi;
21 use middle::trans::common::*;
22 use middle::trans::machine;
23 use middle::trans::type_::Type;
24 use middle::trans::type_of::*;
25 use middle::trans::type_of;
26 use middle::ty::FnSig;
29 use std::libc::c_uint;
30 use syntax::abi::{Cdecl, Aapcs, C, AbiSet, Win64};
31 use syntax::abi::{RustIntrinsic, Rust, Stdcall, Fastcall, System};
32 use syntax::codemap::Span;
33 use syntax::parse::token::{InternedString, special_idents};
34 use syntax::parse::token;
36 use syntax::{attr, ast_map};
37 use util::ppaux::{Repr, UserString};
39 ///////////////////////////////////////////////////////////////////////////
43 /// Rust signature of the function
46 /// Adapter object for handling native ABI rules (trust me, you
47 /// don't want to know)
50 /// LLVM types that will appear on the foreign function
53 /// True if there is a return value (not bottom, not unit)
57 struct LlvmSignature {
58 // LLVM versions of the types of this function's arguments.
59 llarg_tys: Vec<Type> ,
61 // LLVM version of the type that this function returns. Note that
62 // this *may not be* the declared return type of the foreign
63 // function, because the foreign function may opt to return via an
67 // True if *Rust* would use an outpointer for this function.
72 ///////////////////////////////////////////////////////////////////////////
73 // Calls to external functions
75 pub fn llvm_calling_convention(ccx: &CrateContext,
76 abis: AbiSet) -> Option<CallConv> {
77 let os = ccx.sess().targ_cfg.os;
78 let arch = ccx.sess().targ_cfg.arch;
79 abis.for_target(os, arch).map(|abi| {
82 // Intrinsics are emitted by monomorphic fn
83 ccx.sess().bug(format!("asked to register intrinsic fn"));
87 // FIXME(#3678) Implement linking to foreign fns with Rust ABI
89 format!("foreign functions with Rust ABI"));
92 // It's the ABI's job to select this, not us.
93 System => ccx.sess().bug("system abi should be selected elsewhere"),
95 Stdcall => lib::llvm::X86StdcallCallConv,
96 Fastcall => lib::llvm::X86FastcallCallConv,
97 C => lib::llvm::CCallConv,
98 Win64 => lib::llvm::X86_64_Win64,
100 // These API constants ought to be more specific...
101 Cdecl => lib::llvm::CCallConv,
102 Aapcs => lib::llvm::CCallConv,
107 pub fn llvm_linkage_by_name(name: &str) -> Option<Linkage> {
108 // Use the names from src/llvm/docs/LangRef.rst here. Most types are only
109 // applicable to variable declarations and may not really make sense for
110 // Rust code in the first place but whitelist them anyway and trust that
111 // the user knows what s/he's doing. Who knows, unanticipated use cases
112 // may pop up in the future.
114 // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported
115 // and don't have to be, LLVM treats them as no-ops.
117 "appending" => Some(lib::llvm::AppendingLinkage),
118 "available_externally" => Some(lib::llvm::AvailableExternallyLinkage),
119 "common" => Some(lib::llvm::CommonLinkage),
120 "extern_weak" => Some(lib::llvm::ExternalWeakLinkage),
121 "external" => Some(lib::llvm::ExternalLinkage),
122 "internal" => Some(lib::llvm::InternalLinkage),
123 "linkonce" => Some(lib::llvm::LinkOnceAnyLinkage),
124 "linkonce_odr" => Some(lib::llvm::LinkOnceODRLinkage),
125 "private" => Some(lib::llvm::PrivateLinkage),
126 "weak" => Some(lib::llvm::WeakAnyLinkage),
127 "weak_odr" => Some(lib::llvm::WeakODRLinkage),
132 pub fn register_static(ccx: &CrateContext,
133 foreign_item: &ast::ForeignItem) -> ValueRef {
134 let ty = ty::node_id_to_type(ccx.tcx(), foreign_item.id);
135 let llty = type_of::type_of(ccx, ty);
137 // Treat the crate map static specially in order to
138 // a weak-linkage-like functionality where it's
139 // dynamically resolved at runtime. If we're
140 // building a library, then we declare the static
141 // with weak linkage, but if we're building a
142 // library then we've already declared the crate map
143 // so use that instead.
144 if attr::contains_name(foreign_item.attrs.as_slice(), "crate_map") {
145 return if ccx.sess().building_library.get() {
146 let s = "_rust_crate_map_toplevel";
149 llvm::LLVMAddGlobal(ccx.llmod, llty.to_ref(), buf)
152 lib::llvm::SetLinkage(g, lib::llvm::ExternalWeakLinkage);
159 let ident = link_name(foreign_item);
160 match attr::first_attr_value_str_by_name(foreign_item.attrs.as_slice(),
162 // If this is a static with a linkage specified, then we need to handle
163 // it a little specially. The typesystem prevents things like &T and
164 // extern "C" fn() from being non-null, so we can't just declare a
165 // static and call it a day. Some linkages (like weak) will make it such
166 // that the static actually has a null value.
168 let linkage = match llvm_linkage_by_name(name.get()) {
169 Some(linkage) => linkage,
171 ccx.sess().span_fatal(foreign_item.span,
172 "invalid linkage specified");
175 let llty2 = match ty::get(ty).sty {
176 ty::ty_ptr(ref mt) => type_of::type_of(ccx, mt.ty),
178 ccx.sess().span_fatal(foreign_item.span,
179 "must have type `*T` or `*mut T`");
183 let g1 = ident.get().with_c_str(|buf| {
184 llvm::LLVMAddGlobal(ccx.llmod, llty2.to_ref(), buf)
186 lib::llvm::SetLinkage(g1, linkage);
188 let real_name = "_rust_extern_with_linkage_" + ident.get();
189 let g2 = real_name.with_c_str(|buf| {
190 llvm::LLVMAddGlobal(ccx.llmod, llty.to_ref(), buf)
192 lib::llvm::SetLinkage(g2, lib::llvm::InternalLinkage);
193 llvm::LLVMSetInitializer(g2, g1);
198 ident.get().with_c_str(|buf| {
199 llvm::LLVMAddGlobal(ccx.llmod, llty.to_ref(), buf)
205 pub fn register_foreign_item_fn(ccx: &CrateContext, abis: AbiSet,
206 foreign_item: &ast::ForeignItem) -> ValueRef {
208 * Registers a foreign function found in a library.
209 * Just adds a LLVM global.
212 debug!("register_foreign_item_fn(abis={}, \
214 foreign_item.id={})",
215 abis.repr(ccx.tcx()),
216 ccx.tcx.map.path_to_str(foreign_item.id),
219 let cc = match llvm_calling_convention(ccx, abis) {
222 ccx.sess().span_fatal(foreign_item.span,
223 format!("ABI `{}` has no suitable calling convention \
224 for target architecture",
225 abis.user_string(ccx.tcx())));
229 // Register the function as a C extern fn
230 let lname = link_name(foreign_item);
231 let tys = foreign_types_for_id(ccx, foreign_item.id);
233 // Make sure the calling convention is right for variadic functions
234 // (should've been caught if not in typeck)
235 if tys.fn_sig.variadic {
236 assert!(cc == lib::llvm::CCallConv);
239 // Create the LLVM value for the C extern fn
240 let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
244 let mut externs = ccx.externs.borrow_mut();
245 llfn = base::get_extern_fn(externs.get(),
252 add_argument_attributes(&tys, llfn);
257 pub fn trans_native_call<'a>(
262 llargs_rust: &[ValueRef],
263 passed_arg_tys: Vec<ty::t> )
266 * Prepares a call to a native function. This requires adapting
267 * from the Rust argument passing rules to the native rules.
271 * - `callee_ty`: Rust type for the function we are calling
272 * - `llfn`: the function pointer we are calling
273 * - `llretptr`: where to store the return value of the function
274 * - `llargs_rust`: a list of the argument values, prepared
275 * as they would be if calling a Rust function
276 * - `passed_arg_tys`: Rust type for the arguments. Normally we
277 * can derive these from callee_ty but in the case of variadic
278 * functions passed_arg_tys will include the Rust type of all
279 * the arguments including the ones not specified in the fn's signature.
285 debug!("trans_native_call(callee_ty={}, \
289 ccx.tn.val_to_str(llfn),
290 ccx.tn.val_to_str(llretptr));
292 let (fn_abis, fn_sig) = match ty::get(callee_ty).sty {
293 ty::ty_bare_fn(ref fn_ty) => (fn_ty.abis, fn_ty.sig.clone()),
294 _ => ccx.sess().bug("trans_native_call called on non-function type")
296 let llsig = foreign_signature(ccx, &fn_sig, passed_arg_tys.as_slice());
297 let ret_def = !return_type_is_void(bcx.ccx(), fn_sig.output);
298 let fn_type = cabi::compute_abi_info(ccx,
299 llsig.llarg_tys.as_slice(),
303 let arg_tys: &[cabi::ArgType] = fn_type.arg_tys.as_slice();
305 let mut llargs_foreign = Vec::new();
307 // If the foreign ABI expects return value by pointer, supply the
308 // pointer that Rust gave us. Sometimes we have to bitcast
309 // because foreign fns return slightly different (but equivalent)
310 // views on the same type (e.g., i64 in place of {i32,i32}).
311 if fn_type.ret_ty.is_indirect() {
312 match fn_type.ret_ty.cast {
315 BitCast(bcx, llretptr, ty.ptr_to());
316 llargs_foreign.push(llcastedretptr);
319 llargs_foreign.push(llretptr);
324 for (i, &llarg_rust) in llargs_rust.iter().enumerate() {
325 let mut llarg_rust = llarg_rust;
327 if arg_tys[i].is_ignore() {
331 // Does Rust pass this argument by pointer?
332 let rust_indirect = type_of::arg_is_indirect(ccx,
333 *passed_arg_tys.get(i));
335 debug!("argument {}, llarg_rust={}, rust_indirect={}, arg_ty={}",
337 ccx.tn.val_to_str(llarg_rust),
339 ccx.tn.type_to_str(arg_tys[i].ty));
341 // Ensure that we always have the Rust value indirectly,
342 // because it makes bitcasting easier.
346 type_of::type_of(ccx, *passed_arg_tys.get(i)),
348 Store(bcx, llarg_rust, scratch);
349 llarg_rust = scratch;
352 debug!("llarg_rust={} (after indirection)",
353 ccx.tn.val_to_str(llarg_rust));
355 // Check whether we need to do any casting
356 match arg_tys[i].cast {
357 Some(ty) => llarg_rust = BitCast(bcx, llarg_rust, ty.ptr_to()),
361 debug!("llarg_rust={} (after casting)",
362 ccx.tn.val_to_str(llarg_rust));
364 // Finally, load the value if needed for the foreign ABI
365 let foreign_indirect = arg_tys[i].is_indirect();
366 let llarg_foreign = if foreign_indirect {
369 Load(bcx, llarg_rust)
372 debug!("argument {}, llarg_foreign={}",
373 i, ccx.tn.val_to_str(llarg_foreign));
375 // fill padding with undef value
376 match arg_tys[i].pad {
377 Some(ty) => llargs_foreign.push(C_undef(ty)),
380 llargs_foreign.push(llarg_foreign);
383 let cc = match llvm_calling_convention(ccx, fn_abis) {
386 // FIXME(#8357) We really ought to report a span here
388 format!("ABI string `{}` has no suitable ABI \
389 for target architecture",
390 fn_abis.user_string(ccx.tcx())));
394 // A function pointer is called without the declaration available, so we have to apply
395 // any attributes with ABI implications directly to the call instruction. Right now, the
396 // only attribute we need to worry about is `sret`.
397 let sret_attr = if fn_type.ret_ty.is_indirect() {
398 Some((1, StructRetAttribute))
402 let attrs = sret_attr.as_slice();
403 let llforeign_retval = CallWithConv(bcx,
405 llargs_foreign.as_slice(),
409 // If the function we just called does not use an outpointer,
410 // store the result into the rust outpointer. Cast the outpointer
411 // type to match because some ABIs will use a different type than
412 // the Rust type. e.g., a {u32,u32} struct could be returned as
414 if ret_def && !fn_type.ret_ty.is_indirect() {
415 let llrust_ret_ty = llsig.llret_ty;
416 let llforeign_ret_ty = match fn_type.ret_ty.cast {
418 None => fn_type.ret_ty.ty
421 debug!("llretptr={}", ccx.tn.val_to_str(llretptr));
422 debug!("llforeign_retval={}", ccx.tn.val_to_str(llforeign_retval));
423 debug!("llrust_ret_ty={}", ccx.tn.type_to_str(llrust_ret_ty));
424 debug!("llforeign_ret_ty={}", ccx.tn.type_to_str(llforeign_ret_ty));
426 if llrust_ret_ty == llforeign_ret_ty {
427 Store(bcx, llforeign_retval, llretptr);
429 // The actual return type is a struct, but the ABI
430 // adaptation code has cast it into some scalar type. The
431 // code that follows is the only reliable way I have
432 // found to do a transform like i64 -> {i32,i32}.
433 // Basically we dump the data onto the stack then memcpy it.
435 // Other approaches I tried:
436 // - Casting rust ret pointer to the foreign type and using Store
437 // is (a) unsafe if size of foreign type > size of rust type and
438 // (b) runs afoul of strict aliasing rules, yielding invalid
439 // assembly under -O (specifically, the store gets removed).
440 // - Truncating foreign type to correct integral type and then
441 // bitcasting to the struct type yields invalid cast errors.
442 let llscratch = base::alloca(bcx, llforeign_ret_ty, "__cast");
443 Store(bcx, llforeign_retval, llscratch);
444 let llscratch_i8 = BitCast(bcx, llscratch, Type::i8(ccx).ptr_to());
445 let llretptr_i8 = BitCast(bcx, llretptr, Type::i8(ccx).ptr_to());
446 let llrust_size = machine::llsize_of_store(ccx, llrust_ret_ty);
447 let llforeign_align = machine::llalign_of_min(ccx, llforeign_ret_ty);
448 let llrust_align = machine::llalign_of_min(ccx, llrust_ret_ty);
449 let llalign = cmp::min(llforeign_align, llrust_align);
450 debug!("llrust_size={:?}", llrust_size);
451 base::call_memcpy(bcx, llretptr_i8, llscratch_i8,
452 C_uint(ccx, llrust_size as uint), llalign as u32);
459 pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &ast::ForeignMod) {
460 let _icx = push_ctxt("foreign::trans_foreign_mod");
461 for &foreign_item in foreign_mod.items.iter() {
462 match foreign_item.node {
463 ast::ForeignItemFn(..) => {
464 let abis = foreign_mod.abis;
465 if !(abis.is_rust() || abis.is_intrinsic()) {
466 register_foreign_item_fn(ccx, abis, foreign_item);
472 let lname = link_name(foreign_item);
473 let mut item_symbols = ccx.item_symbols.borrow_mut();
474 item_symbols.get().insert(foreign_item.id, lname.get().to_owned());
478 ///////////////////////////////////////////////////////////////////////////
479 // Rust functions with foreign ABIs
481 // These are normal Rust functions defined with foreign ABIs. For
482 // now, and perhaps forever, we translate these using a "layer of
483 // indirection". That is, given a Rust declaration like:
485 // extern "C" fn foo(i: u32) -> u32 { ... }
487 // we will generate a function like:
491 // foo0(&r, NULL, i);
496 // void foo0(uint32_t *r, void *env, uint32_t i) { ... }
498 // Here the (internal) `foo0` function follows the Rust ABI as normal,
499 // where the `foo` function follows the C ABI. We rely on LLVM to
500 // inline the one into the other. Of course we could just generate the
501 // correct code in the first place, but this is much simpler.
503 pub fn register_rust_fn_with_foreign_abi(ccx: &CrateContext,
506 node_id: ast::NodeId)
508 let _icx = push_ctxt("foreign::register_foreign_fn");
510 let tys = foreign_types_for_id(ccx, node_id);
511 let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
512 let t = ty::node_id_to_type(ccx.tcx(), node_id);
513 let (cconv, output) = match ty::get(t).sty {
514 ty::ty_bare_fn(ref fn_ty) => {
515 let c = llvm_calling_convention(ccx, fn_ty.abis);
516 (c.unwrap_or(lib::llvm::CCallConv), fn_ty.sig.output)
518 _ => fail!("expected bare fn in register_rust_fn_with_foreign_abi")
520 let llfn = base::register_fn_llvmty(ccx, sp, sym, node_id, cconv, llfn_ty, output);
521 add_argument_attributes(&tys, llfn);
522 debug!("register_rust_fn_with_foreign_abi(node_id={:?}, llfn_ty={}, llfn={})",
523 node_id, ccx.tn.type_to_str(llfn_ty), ccx.tn.val_to_str(llfn));
527 pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext,
530 attrs: &[ast::Attribute],
533 let _icx = push_ctxt("foreign::build_foreign_fn");
534 let tys = foreign_types_for_id(ccx, id);
536 unsafe { // unsafe because we call LLVM operations
537 // Build up the Rust function (`foo0` above).
538 let llrustfn = build_rust_fn(ccx, decl, body, attrs, id);
540 // Build up the foreign wrapper (`foo` above).
541 return build_wrap_fn(ccx, llrustfn, llwrapfn, &tys);
544 fn build_rust_fn(ccx: &CrateContext,
547 attrs: &[ast::Attribute],
550 let _icx = push_ctxt("foreign::foreign::build_rust_fn");
552 let t = ty::node_id_to_type(tcx, id);
554 let ps = ccx.tcx.map.with_path(id, |path| {
555 let abi = Some(ast_map::PathName(special_idents::clownshoe_abi.name));
556 link::mangle(path.chain(abi.move_iter()), None, None)
559 // Compute the type that the function would have if it were just a
560 // normal Rust function. This will be the type of the wrappee fn.
561 let f = match ty::get(t).sty {
562 ty::ty_bare_fn(ref f) => {
563 assert!(!f.abis.is_rust() && !f.abis.is_intrinsic());
567 ccx.sess().bug(format!("build_rust_fn: extern fn {} has ty {}, \
568 expected a bare fn ty",
569 ccx.tcx.map.path_to_str(id),
574 debug!("build_rust_fn: path={} id={} t={}",
575 ccx.tcx.map.path_to_str(id),
578 let llfn = base::decl_internal_rust_fn(ccx,
580 f.sig.inputs.as_slice(),
583 base::set_llvm_fn_attrs(attrs, llfn);
584 base::trans_fn(ccx, decl, body, llfn, None, id, []);
588 unsafe fn build_wrap_fn(ccx: &CrateContext,
591 tys: &ForeignTypes) {
592 let _icx = push_ctxt(
593 "foreign::trans_rust_fn_with_foreign_abi::build_wrap_fn");
596 debug!("build_wrap_fn(llrustfn={}, llwrapfn={})",
597 ccx.tn.val_to_str(llrustfn),
598 ccx.tn.val_to_str(llwrapfn));
600 // Avoid all the Rust generation stuff and just generate raw
603 // We want to generate code like this:
607 // foo0(&r, NULL, i);
612 "the block".with_c_str(
613 |s| llvm::LLVMAppendBasicBlockInContext(ccx.llcx, llwrapfn, s));
615 let builder = ccx.builder.b;
616 llvm::LLVMPositionBuilderAtEnd(builder, the_block);
618 // Array for the arguments we will pass to the rust function.
619 let mut llrust_args = Vec::new();
620 let mut next_foreign_arg_counter: c_uint = 0;
621 let next_foreign_arg: |pad: bool| -> c_uint = |pad: bool| {
622 next_foreign_arg_counter += if pad {
627 next_foreign_arg_counter - 1
630 // If there is an out pointer on the foreign function
631 let foreign_outptr = {
632 if tys.fn_ty.ret_ty.is_indirect() {
633 Some(llvm::LLVMGetParam(llwrapfn, next_foreign_arg(false)))
639 // Push Rust return pointer, using null if it will be unused.
640 let rust_uses_outptr =
641 type_of::return_uses_outptr(ccx, tys.fn_sig.output);
642 let return_alloca: Option<ValueRef>;
643 let llrust_ret_ty = tys.llsig.llret_ty;
644 let llrust_retptr_ty = llrust_ret_ty.ptr_to();
645 if rust_uses_outptr {
646 // Rust expects to use an outpointer. If the foreign fn
647 // also uses an outpointer, we can reuse it, but the types
648 // may vary, so cast first to the Rust type. If the
649 // foreign fn does NOT use an outpointer, we will have to
650 // alloca some scratch space on the stack.
651 match foreign_outptr {
652 Some(llforeign_outptr) => {
653 debug!("out pointer, foreign={}",
654 ccx.tn.val_to_str(llforeign_outptr));
656 llvm::LLVMBuildBitCast(builder,
658 llrust_ret_ty.ptr_to().to_ref(),
660 debug!("out pointer, foreign={} (casted)",
661 ccx.tn.val_to_str(llrust_retptr));
662 llrust_args.push(llrust_retptr);
663 return_alloca = None;
668 "return_alloca".with_c_str(
669 |s| llvm::LLVMBuildAlloca(builder,
670 llrust_ret_ty.to_ref(),
673 debug!("out pointer, \
677 ccx.tn.val_to_str(slot),
678 ccx.tn.type_to_str(llrust_ret_ty),
679 tys.fn_sig.output.repr(tcx));
680 llrust_args.push(slot);
681 return_alloca = Some(slot);
685 // Rust does not expect an outpointer. If the foreign fn
686 // does use an outpointer, then we will do a store of the
687 // value that the Rust fn returns.
688 return_alloca = None;
691 // Build up the arguments to the call to the rust function.
692 // Careful to adapt for cases where the native convention uses
693 // a pointer and Rust does not or vice versa.
694 for i in range(0, tys.fn_sig.inputs.len()) {
695 let rust_ty = *tys.fn_sig.inputs.get(i);
696 let llrust_ty = *tys.llsig.llarg_tys.get(i);
697 let rust_indirect = type_of::arg_is_indirect(ccx, rust_ty);
698 let llforeign_arg_ty = *tys.fn_ty.arg_tys.get(i);
699 let foreign_indirect = llforeign_arg_ty.is_indirect();
702 let foreign_index = next_foreign_arg(llforeign_arg_ty.pad.is_some());
703 let mut llforeign_arg = llvm::LLVMGetParam(llwrapfn, foreign_index);
705 debug!("llforeign_arg \\#{}: {}",
706 i, ccx.tn.val_to_str(llforeign_arg));
707 debug!("rust_indirect = {}, foreign_indirect = {}",
708 rust_indirect, foreign_indirect);
710 // Ensure that the foreign argument is indirect (by
711 // pointer). It makes adapting types easier, since we can
712 // always just bitcast pointers.
713 if !foreign_indirect {
715 llvm::LLVMBuildAlloca(
716 builder, val_ty(llforeign_arg).to_ref(), noname());
717 llvm::LLVMBuildStore(
718 builder, llforeign_arg, lltemp);
719 llforeign_arg = lltemp;
722 // If the types in the ABI and the Rust types don't match,
723 // bitcast the llforeign_arg pointer so it matches the types
725 if llforeign_arg_ty.cast.is_some() {
726 assert!(!foreign_indirect);
727 llforeign_arg = llvm::LLVMBuildBitCast(
728 builder, llforeign_arg,
729 llrust_ty.ptr_to().to_ref(), noname());
732 let llrust_arg = if rust_indirect {
735 llvm::LLVMBuildLoad(builder, llforeign_arg, noname())
738 debug!("llrust_arg \\#{}: {}",
739 i, ccx.tn.val_to_str(llrust_arg));
740 llrust_args.push(llrust_arg);
743 // Perform the call itself
744 debug!("calling llrustfn = {}", ccx.tn.val_to_str(llrustfn));
745 let llrust_ret_val = llvm::LLVMBuildCall(builder, llrustfn, llrust_args.as_ptr(),
746 llrust_args.len() as c_uint, noname());
748 // Get the return value where the foreign fn expects it.
749 let llforeign_ret_ty = match tys.fn_ty.ret_ty.cast {
751 None => tys.fn_ty.ret_ty.ty
753 match foreign_outptr {
754 None if !tys.ret_def => {
755 // Function returns `()` or `bot`, which in Rust is the LLVM
756 // type "{}" but in foreign ABIs is "Void".
757 llvm::LLVMBuildRetVoid(builder);
760 None if rust_uses_outptr => {
761 // Rust uses an outpointer, but the foreign ABI does not. Load.
762 let llrust_outptr = return_alloca.unwrap();
763 let llforeign_outptr_casted =
764 llvm::LLVMBuildBitCast(builder,
766 llforeign_ret_ty.ptr_to().to_ref(),
768 let llforeign_retval =
769 llvm::LLVMBuildLoad(builder, llforeign_outptr_casted, noname());
770 llvm::LLVMBuildRet(builder, llforeign_retval);
773 None if llforeign_ret_ty != llrust_ret_ty => {
774 // Neither ABI uses an outpointer, but the types don't
775 // quite match. Must cast. Probably we should try and
776 // examine the types and use a concrete llvm cast, but
777 // right now we just use a temp memory location and
778 // bitcast the pointer, which is the same thing the
779 // old wrappers used to do.
781 llvm::LLVMBuildAlloca(
782 builder, llforeign_ret_ty.to_ref(), noname());
784 llvm::LLVMBuildBitCast(builder,
786 llrust_ret_ty.ptr_to().to_ref(),
788 llvm::LLVMBuildStore(
789 builder, llrust_ret_val, lltemp_casted);
790 let llforeign_retval =
791 llvm::LLVMBuildLoad(builder, lltemp, noname());
792 llvm::LLVMBuildRet(builder, llforeign_retval);
796 // Neither ABI uses an outpointer, and the types
797 // match. Easy peasy.
798 llvm::LLVMBuildRet(builder, llrust_ret_val);
801 Some(llforeign_outptr) if !rust_uses_outptr => {
802 // Foreign ABI requires an out pointer, but Rust doesn't.
803 // Store Rust return value.
804 let llforeign_outptr_casted =
805 llvm::LLVMBuildBitCast(builder,
807 llrust_retptr_ty.to_ref(),
809 llvm::LLVMBuildStore(
810 builder, llrust_ret_val, llforeign_outptr_casted);
811 llvm::LLVMBuildRetVoid(builder);
815 // Both ABIs use outpointers. Easy peasy.
816 llvm::LLVMBuildRetVoid(builder);
822 ///////////////////////////////////////////////////////////////////////////
823 // General ABI Support
825 // This code is kind of a confused mess and needs to be reworked given
826 // the massive simplifications that have occurred.
828 pub fn link_name(i: &ast::ForeignItem) -> InternedString {
829 match attr::first_attr_value_str_by_name(i.attrs.as_slice(),
831 None => token::get_ident(i.ident),
832 Some(ln) => ln.clone(),
836 fn foreign_signature(ccx: &CrateContext, fn_sig: &ty::FnSig, arg_tys: &[ty::t])
839 * The ForeignSignature is the LLVM types of the arguments/return type
840 * of a function. Note that these LLVM types are not quite the same
841 * as the LLVM types would be for a native Rust function because foreign
842 * functions just plain ignore modes. They also don't pass aggregate
843 * values by pointer like we do.
846 let llarg_tys = arg_tys.iter().map(|&arg| type_of(ccx, arg)).collect();
847 let llret_ty = type_of::type_of(ccx, fn_sig.output);
849 llarg_tys: llarg_tys,
851 sret: type_of::return_uses_outptr(ccx, fn_sig.output),
855 fn foreign_types_for_id(ccx: &CrateContext,
856 id: ast::NodeId) -> ForeignTypes {
857 foreign_types_for_fn_ty(ccx, ty::node_id_to_type(ccx.tcx(), id))
860 fn foreign_types_for_fn_ty(ccx: &CrateContext,
861 ty: ty::t) -> ForeignTypes {
862 let fn_sig = match ty::get(ty).sty {
863 ty::ty_bare_fn(ref fn_ty) => fn_ty.sig.clone(),
864 _ => ccx.sess().bug("foreign_types_for_fn_ty called on non-function type")
866 let llsig = foreign_signature(ccx, &fn_sig, fn_sig.inputs.as_slice());
867 let ret_def = !return_type_is_void(ccx, fn_sig.output);
868 let fn_ty = cabi::compute_abi_info(ccx,
869 llsig.llarg_tys.as_slice(),
872 debug!("foreign_types_for_fn_ty(\
878 ccx.tn.types_to_str(llsig.llarg_tys.as_slice()),
879 ccx.tn.type_to_str(llsig.llret_ty),
880 ccx.tn.types_to_str(fn_ty.arg_tys.map(|t| t.ty).as_slice()),
881 ccx.tn.type_to_str(fn_ty.ret_ty.ty),
892 fn lltype_for_fn_from_foreign_types(ccx: &CrateContext, tys: &ForeignTypes) -> Type {
893 let mut llargument_tys = Vec::new();
895 let ret_ty = tys.fn_ty.ret_ty;
896 let llreturn_ty = if ret_ty.is_indirect() {
897 llargument_tys.push(ret_ty.ty.ptr_to());
906 for &arg_ty in tys.fn_ty.arg_tys.iter() {
907 if arg_ty.is_ignore() {
912 Some(ty) => llargument_tys.push(ty),
916 let llarg_ty = if arg_ty.is_indirect() {
925 llargument_tys.push(llarg_ty);
928 if tys.fn_sig.variadic {
929 Type::variadic_func(llargument_tys.as_slice(), &llreturn_ty)
931 Type::func(llargument_tys.as_slice(), &llreturn_ty)
935 pub fn lltype_for_foreign_fn(ccx: &CrateContext, ty: ty::t) -> Type {
936 lltype_for_fn_from_foreign_types(ccx, &foreign_types_for_fn_ty(ccx, ty))
939 fn add_argument_attributes(tys: &ForeignTypes,
943 if tys.fn_ty.ret_ty.is_indirect() {
944 match tys.fn_ty.ret_ty.attr {
946 let llarg = get_param(llfn, i);
948 llvm::LLVMAddAttribute(llarg, attr as c_uint);
957 for &arg_ty in tys.fn_ty.arg_tys.iter() {
958 if arg_ty.is_ignore() {
962 if arg_ty.pad.is_some() { i += 1; }
966 let llarg = get_param(llfn, i);
968 llvm::LLVMAddAttribute(llarg, attr as c_uint);