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.
13 use llvm::{ValueRef, CallConv, Linkage, get_param};
15 use middle::weak_lang_items;
16 use middle::trans::base::push_ctxt;
17 use middle::trans::base;
18 use middle::trans::build::*;
19 use middle::trans::cabi;
20 use middle::trans::common::*;
21 use middle::trans::machine;
22 use middle::trans::type_::Type;
23 use middle::trans::type_of::*;
24 use middle::trans::type_of;
25 use middle::ty::FnSig;
29 use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi};
30 use syntax::abi::{RustIntrinsic, Rust, RustCall, Stdcall, Fastcall, System};
31 use syntax::codemap::Span;
32 use syntax::parse::token::{InternedString, special_idents};
33 use syntax::parse::token;
35 use syntax::{attr, ast_map};
36 use util::ppaux::{Repr, UserString};
38 ///////////////////////////////////////////////////////////////////////////
42 /// Rust signature of the function
45 /// Adapter object for handling native ABI rules (trust me, you
46 /// don't want to know)
49 /// LLVM types that will appear on the foreign function
52 /// True if there is a return value (not bottom, not unit)
56 struct LlvmSignature {
57 // LLVM versions of the types of this function's arguments.
58 llarg_tys: Vec<Type> ,
60 // LLVM version of the type that this function returns. Note that
61 // this *may not be* the declared return type of the foreign
62 // function, because the foreign function may opt to return via an
68 ///////////////////////////////////////////////////////////////////////////
69 // Calls to external functions
71 pub fn llvm_calling_convention(ccx: &CrateContext,
72 abi: Abi) -> Option<CallConv> {
73 let os = ccx.sess().targ_cfg.os;
74 let arch = ccx.sess().targ_cfg.arch;
75 abi.for_target(os, arch).map(|abi| {
78 // Intrinsics are emitted at the call site
79 ccx.sess().bug("asked to register intrinsic fn");
83 // FIXME(#3678) Implement linking to foreign fns with Rust ABI
84 ccx.sess().unimpl("foreign functions with Rust ABI");
88 // FIXME(#3678) Implement linking to foreign fns with Rust ABI
89 ccx.sess().unimpl("foreign functions with RustCall 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 => llvm::X86StdcallCallConv,
96 Fastcall => llvm::X86FastcallCallConv,
98 Win64 => llvm::X86_64_Win64,
100 // These API constants ought to be more specific...
101 Cdecl => llvm::CCallConv,
102 Aapcs => 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(llvm::AppendingLinkage),
118 "available_externally" => Some(llvm::AvailableExternallyLinkage),
119 "common" => Some(llvm::CommonLinkage),
120 "extern_weak" => Some(llvm::ExternalWeakLinkage),
121 "external" => Some(llvm::ExternalLinkage),
122 "internal" => Some(llvm::InternalLinkage),
123 "linkonce" => Some(llvm::LinkOnceAnyLinkage),
124 "linkonce_odr" => Some(llvm::LinkOnceODRLinkage),
125 "private" => Some(llvm::PrivateLinkage),
126 "weak" => Some(llvm::WeakAnyLinkage),
127 "weak_odr" => Some(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 let ident = link_name(foreign_item);
138 match attr::first_attr_value_str_by_name(foreign_item.attrs.as_slice(),
140 // If this is a static with a linkage specified, then we need to handle
141 // it a little specially. The typesystem prevents things like &T and
142 // extern "C" fn() from being non-null, so we can't just declare a
143 // static and call it a day. Some linkages (like weak) will make it such
144 // that the static actually has a null value.
146 let linkage = match llvm_linkage_by_name(name.get()) {
147 Some(linkage) => linkage,
149 ccx.sess().span_fatal(foreign_item.span,
150 "invalid linkage specified");
153 let llty2 = match ty::get(ty).sty {
154 ty::ty_ptr(ref mt) => type_of::type_of(ccx, mt.ty),
156 ccx.sess().span_fatal(foreign_item.span,
157 "must have type `*T` or `*mut T`");
161 let g1 = ident.get().with_c_str(|buf| {
162 llvm::LLVMAddGlobal(ccx.llmod, llty2.to_ref(), buf)
164 llvm::SetLinkage(g1, linkage);
166 let mut real_name = "_rust_extern_with_linkage_".to_string();
167 real_name.push_str(ident.get());
168 let g2 = real_name.with_c_str(|buf| {
169 llvm::LLVMAddGlobal(ccx.llmod, llty.to_ref(), buf)
171 llvm::SetLinkage(g2, llvm::InternalLinkage);
172 llvm::LLVMSetInitializer(g2, g1);
177 ident.get().with_c_str(|buf| {
178 llvm::LLVMAddGlobal(ccx.llmod, llty.to_ref(), buf)
184 pub fn register_foreign_item_fn(ccx: &CrateContext, abi: Abi, fty: ty::t,
185 name: &str, span: Option<Span>) -> ValueRef {
187 * Registers a foreign function found in a library.
188 * Just adds a LLVM global.
191 debug!("register_foreign_item_fn(abi={}, \
198 let cc = match llvm_calling_convention(ccx, abi) {
203 ccx.sess().span_fatal(s,
204 format!("ABI `{}` has no suitable calling convention \
205 for target architecture",
206 abi.user_string(ccx.tcx())).as_slice())
210 format!("ABI `{}` has no suitable calling convention \
211 for target architecture",
212 abi.user_string(ccx.tcx())).as_slice())
218 // Register the function as a C extern fn
219 let tys = foreign_types_for_fn_ty(ccx, fty);
221 // Make sure the calling convention is right for variadic functions
222 // (should've been caught if not in typeck)
223 if tys.fn_sig.variadic {
224 assert!(cc == llvm::CCallConv);
227 // Create the LLVM value for the C extern fn
228 let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
230 let llfn = base::get_extern_fn(ccx,
231 &mut *ccx.externs.borrow_mut(),
236 add_argument_attributes(&tys, llfn);
241 pub fn trans_native_call<'a>(
246 llargs_rust: &[ValueRef],
247 passed_arg_tys: Vec<ty::t> )
250 * Prepares a call to a native function. This requires adapting
251 * from the Rust argument passing rules to the native rules.
255 * - `callee_ty`: Rust type for the function we are calling
256 * - `llfn`: the function pointer we are calling
257 * - `llretptr`: where to store the return value of the function
258 * - `llargs_rust`: a list of the argument values, prepared
259 * as they would be if calling a Rust function
260 * - `passed_arg_tys`: Rust type for the arguments. Normally we
261 * can derive these from callee_ty but in the case of variadic
262 * functions passed_arg_tys will include the Rust type of all
263 * the arguments including the ones not specified in the fn's signature.
269 debug!("trans_native_call(callee_ty={}, \
273 ccx.tn.val_to_string(llfn),
274 ccx.tn.val_to_string(llretptr));
276 let (fn_abi, fn_sig) = match ty::get(callee_ty).sty {
277 ty::ty_bare_fn(ref fn_ty) => (fn_ty.abi, fn_ty.sig.clone()),
278 _ => ccx.sess().bug("trans_native_call called on non-function type")
280 let llsig = foreign_signature(ccx, &fn_sig, passed_arg_tys.as_slice());
281 let ret_def = !return_type_is_void(bcx.ccx(), fn_sig.output);
282 let fn_type = cabi::compute_abi_info(ccx,
283 llsig.llarg_tys.as_slice(),
287 let arg_tys: &[cabi::ArgType] = fn_type.arg_tys.as_slice();
289 let mut llargs_foreign = Vec::new();
291 // If the foreign ABI expects return value by pointer, supply the
292 // pointer that Rust gave us. Sometimes we have to bitcast
293 // because foreign fns return slightly different (but equivalent)
294 // views on the same type (e.g., i64 in place of {i32,i32}).
295 if fn_type.ret_ty.is_indirect() {
296 match fn_type.ret_ty.cast {
299 BitCast(bcx, llretptr, ty.ptr_to());
300 llargs_foreign.push(llcastedretptr);
303 llargs_foreign.push(llretptr);
308 for (i, &llarg_rust) in llargs_rust.iter().enumerate() {
309 let mut llarg_rust = llarg_rust;
311 if arg_tys[i].is_ignore() {
315 // Does Rust pass this argument by pointer?
316 let rust_indirect = type_of::arg_is_indirect(ccx,
317 *passed_arg_tys.get(i));
319 debug!("argument {}, llarg_rust={}, rust_indirect={}, arg_ty={}",
321 ccx.tn.val_to_string(llarg_rust),
323 ccx.tn.type_to_string(arg_tys[i].ty));
325 // Ensure that we always have the Rust value indirectly,
326 // because it makes bitcasting easier.
330 type_of::type_of(ccx, *passed_arg_tys.get(i)),
332 base::store_ty(bcx, llarg_rust, scratch, *passed_arg_tys.get(i));
333 llarg_rust = scratch;
336 debug!("llarg_rust={} (after indirection)",
337 ccx.tn.val_to_string(llarg_rust));
339 // Check whether we need to do any casting
340 match arg_tys[i].cast {
341 Some(ty) => llarg_rust = BitCast(bcx, llarg_rust, ty.ptr_to()),
345 debug!("llarg_rust={} (after casting)",
346 ccx.tn.val_to_string(llarg_rust));
348 // Finally, load the value if needed for the foreign ABI
349 let foreign_indirect = arg_tys[i].is_indirect();
350 let llarg_foreign = if foreign_indirect {
353 if ty::type_is_bool(*passed_arg_tys.get(i)) {
354 let val = LoadRangeAssert(bcx, llarg_rust, 0, 2, llvm::False);
355 Trunc(bcx, val, Type::i1(bcx.ccx()))
357 Load(bcx, llarg_rust)
361 debug!("argument {}, llarg_foreign={}",
362 i, ccx.tn.val_to_string(llarg_foreign));
364 // fill padding with undef value
365 match arg_tys[i].pad {
366 Some(ty) => llargs_foreign.push(C_undef(ty)),
369 llargs_foreign.push(llarg_foreign);
372 let cc = match llvm_calling_convention(ccx, fn_abi) {
375 // FIXME(#8357) We really ought to report a span here
377 format!("ABI string `{}` has no suitable ABI \
378 for target architecture",
379 fn_abi.user_string(ccx.tcx())).as_slice());
383 // A function pointer is called without the declaration available, so we have to apply
384 // any attributes with ABI implications directly to the call instruction.
385 let mut attrs = llvm::AttrBuilder::new();
387 // Add attributes that are always applicable, independent of the concrete foreign ABI
388 if fn_type.ret_ty.is_indirect() {
389 let llret_sz = machine::llsize_of_real(ccx, fn_type.ret_ty.ty);
391 // The outptr can be noalias and nocapture because it's entirely
392 // invisible to the program. We also know it's nonnull as well
393 // as how many bytes we can dereference
394 attrs.arg(1, llvm::NoAliasAttribute)
395 .arg(1, llvm::NoCaptureAttribute)
396 .arg(1, llvm::DereferenceableAttribute(llret_sz));
399 // Add attributes that depend on the concrete foreign ABI
400 let mut arg_idx = if fn_type.ret_ty.is_indirect() { 1 } else { 0 };
401 match fn_type.ret_ty.attr {
402 Some(attr) => { attrs.arg(arg_idx, attr); },
407 for arg_ty in fn_type.arg_tys.iter() {
408 if arg_ty.is_ignore() {
412 if arg_ty.pad.is_some() { arg_idx += 1; }
415 Some(attr) => { attrs.arg(arg_idx, attr); },
422 let llforeign_retval = CallWithConv(bcx,
424 llargs_foreign.as_slice(),
428 // If the function we just called does not use an outpointer,
429 // store the result into the rust outpointer. Cast the outpointer
430 // type to match because some ABIs will use a different type than
431 // the Rust type. e.g., a {u32,u32} struct could be returned as
433 if ret_def && !fn_type.ret_ty.is_indirect() {
434 let llrust_ret_ty = llsig.llret_ty;
435 let llforeign_ret_ty = match fn_type.ret_ty.cast {
437 None => fn_type.ret_ty.ty
440 debug!("llretptr={}", ccx.tn.val_to_string(llretptr));
441 debug!("llforeign_retval={}", ccx.tn.val_to_string(llforeign_retval));
442 debug!("llrust_ret_ty={}", ccx.tn.type_to_string(llrust_ret_ty));
443 debug!("llforeign_ret_ty={}", ccx.tn.type_to_string(llforeign_ret_ty));
445 if llrust_ret_ty == llforeign_ret_ty {
446 base::store_ty(bcx, llforeign_retval, llretptr, fn_sig.output)
448 // The actual return type is a struct, but the ABI
449 // adaptation code has cast it into some scalar type. The
450 // code that follows is the only reliable way I have
451 // found to do a transform like i64 -> {i32,i32}.
452 // Basically we dump the data onto the stack then memcpy it.
454 // Other approaches I tried:
455 // - Casting rust ret pointer to the foreign type and using Store
456 // is (a) unsafe if size of foreign type > size of rust type and
457 // (b) runs afoul of strict aliasing rules, yielding invalid
458 // assembly under -O (specifically, the store gets removed).
459 // - Truncating foreign type to correct integral type and then
460 // bitcasting to the struct type yields invalid cast errors.
461 let llscratch = base::alloca(bcx, llforeign_ret_ty, "__cast");
462 Store(bcx, llforeign_retval, llscratch);
463 let llscratch_i8 = BitCast(bcx, llscratch, Type::i8(ccx).ptr_to());
464 let llretptr_i8 = BitCast(bcx, llretptr, Type::i8(ccx).ptr_to());
465 let llrust_size = machine::llsize_of_store(ccx, llrust_ret_ty);
466 let llforeign_align = machine::llalign_of_min(ccx, llforeign_ret_ty);
467 let llrust_align = machine::llalign_of_min(ccx, llrust_ret_ty);
468 let llalign = cmp::min(llforeign_align, llrust_align);
469 debug!("llrust_size={:?}", llrust_size);
470 base::call_memcpy(bcx, llretptr_i8, llscratch_i8,
471 C_uint(ccx, llrust_size as uint), llalign as u32);
478 pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &ast::ForeignMod) {
479 let _icx = push_ctxt("foreign::trans_foreign_mod");
480 for foreign_item in foreign_mod.items.iter() {
481 let lname = link_name(&**foreign_item);
483 match foreign_item.node {
484 ast::ForeignItemFn(..) => {
485 match foreign_mod.abi {
486 Rust | RustIntrinsic => {}
488 let ty = ty::node_id_to_type(ccx.tcx(), foreign_item.id);
489 register_foreign_item_fn(ccx, abi, ty,
490 lname.get().as_slice(),
491 Some(foreign_item.span));
498 ccx.item_symbols.borrow_mut().insert(foreign_item.id,
499 lname.get().to_string());
503 ///////////////////////////////////////////////////////////////////////////
504 // Rust functions with foreign ABIs
506 // These are normal Rust functions defined with foreign ABIs. For
507 // now, and perhaps forever, we translate these using a "layer of
508 // indirection". That is, given a Rust declaration like:
510 // extern "C" fn foo(i: u32) -> u32 { ... }
512 // we will generate a function like:
516 // foo0(&r, NULL, i);
521 // void foo0(uint32_t *r, void *env, uint32_t i) { ... }
523 // Here the (internal) `foo0` function follows the Rust ABI as normal,
524 // where the `foo` function follows the C ABI. We rely on LLVM to
525 // inline the one into the other. Of course we could just generate the
526 // correct code in the first place, but this is much simpler.
528 pub fn register_rust_fn_with_foreign_abi(ccx: &CrateContext,
531 node_id: ast::NodeId)
533 let _icx = push_ctxt("foreign::register_foreign_fn");
535 let tys = foreign_types_for_id(ccx, node_id);
536 let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
537 let t = ty::node_id_to_type(ccx.tcx(), node_id);
538 let cconv = match ty::get(t).sty {
539 ty::ty_bare_fn(ref fn_ty) => {
540 let c = llvm_calling_convention(ccx, fn_ty.abi);
541 c.unwrap_or(llvm::CCallConv)
543 _ => fail!("expected bare fn in register_rust_fn_with_foreign_abi")
545 let llfn = base::register_fn_llvmty(ccx, sp, sym, node_id, cconv, llfn_ty);
546 add_argument_attributes(&tys, llfn);
547 debug!("register_rust_fn_with_foreign_abi(node_id={:?}, llfn_ty={}, llfn={})",
548 node_id, ccx.tn.type_to_string(llfn_ty), ccx.tn.val_to_string(llfn));
552 pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext,
555 attrs: &[ast::Attribute],
558 let _icx = push_ctxt("foreign::build_foreign_fn");
559 let tys = foreign_types_for_id(ccx, id);
561 unsafe { // unsafe because we call LLVM operations
562 // Build up the Rust function (`foo0` above).
563 let llrustfn = build_rust_fn(ccx, decl, body, attrs, id);
565 // Build up the foreign wrapper (`foo` above).
566 return build_wrap_fn(ccx, llrustfn, llwrapfn, &tys, id);
569 fn build_rust_fn(ccx: &CrateContext,
572 attrs: &[ast::Attribute],
575 let _icx = push_ctxt("foreign::foreign::build_rust_fn");
577 let t = ty::node_id_to_type(tcx, id);
579 let ps = ccx.tcx.map.with_path(id, |path| {
580 let abi = Some(ast_map::PathName(special_idents::clownshoe_abi.name));
581 link::mangle(path.chain(abi.move_iter()), None)
584 // Compute the type that the function would have if it were just a
585 // normal Rust function. This will be the type of the wrappee fn.
586 match ty::get(t).sty {
587 ty::ty_bare_fn(ref f) => {
588 assert!(f.abi != Rust && f.abi != RustIntrinsic);
591 ccx.sess().bug(format!("build_rust_fn: extern fn {} has ty {}, \
592 expected a bare fn ty",
593 ccx.tcx.map.path_to_string(id),
594 t.repr(tcx)).as_slice());
598 debug!("build_rust_fn: path={} id={} t={}",
599 ccx.tcx.map.path_to_string(id),
602 let llfn = base::decl_internal_rust_fn(ccx, t, ps.as_slice());
603 base::set_llvm_fn_attrs(attrs, llfn);
604 base::trans_fn(ccx, decl, body, llfn, ¶m_substs::empty(), id, [],
609 unsafe fn build_wrap_fn(ccx: &CrateContext,
614 let _icx = push_ctxt(
615 "foreign::trans_rust_fn_with_foreign_abi::build_wrap_fn");
618 let t = ty::node_id_to_type(tcx, id);
620 debug!("build_wrap_fn(llrustfn={}, llwrapfn={}, t={})",
621 ccx.tn.val_to_string(llrustfn),
622 ccx.tn.val_to_string(llwrapfn),
625 // Avoid all the Rust generation stuff and just generate raw
628 // We want to generate code like this:
632 // foo0(&r, NULL, i);
637 "the block".with_c_str(
638 |s| llvm::LLVMAppendBasicBlockInContext(ccx.llcx, llwrapfn, s));
640 let builder = ccx.builder();
641 builder.position_at_end(the_block);
643 // Array for the arguments we will pass to the rust function.
644 let mut llrust_args = Vec::new();
645 let mut next_foreign_arg_counter: c_uint = 0;
646 let next_foreign_arg: |pad: bool| -> c_uint = |pad: bool| {
647 next_foreign_arg_counter += if pad {
652 next_foreign_arg_counter - 1
655 // If there is an out pointer on the foreign function
656 let foreign_outptr = {
657 if tys.fn_ty.ret_ty.is_indirect() {
658 Some(get_param(llwrapfn, next_foreign_arg(false)))
664 // Push Rust return pointer, using null if it will be unused.
665 let rust_uses_outptr =
666 type_of::return_uses_outptr(ccx, tys.fn_sig.output);
667 let return_alloca: Option<ValueRef>;
668 let llrust_ret_ty = tys.llsig.llret_ty;
669 let llrust_retptr_ty = llrust_ret_ty.ptr_to();
670 if rust_uses_outptr {
671 // Rust expects to use an outpointer. If the foreign fn
672 // also uses an outpointer, we can reuse it, but the types
673 // may vary, so cast first to the Rust type. If the
674 // foreign fn does NOT use an outpointer, we will have to
675 // alloca some scratch space on the stack.
676 match foreign_outptr {
677 Some(llforeign_outptr) => {
678 debug!("out pointer, foreign={}",
679 ccx.tn.val_to_string(llforeign_outptr));
681 builder.bitcast(llforeign_outptr, llrust_ret_ty.ptr_to());
682 debug!("out pointer, foreign={} (casted)",
683 ccx.tn.val_to_string(llrust_retptr));
684 llrust_args.push(llrust_retptr);
685 return_alloca = None;
689 let slot = builder.alloca(llrust_ret_ty, "return_alloca");
690 debug!("out pointer, \
694 ccx.tn.val_to_string(slot),
695 ccx.tn.type_to_string(llrust_ret_ty),
696 tys.fn_sig.output.repr(tcx));
697 llrust_args.push(slot);
698 return_alloca = Some(slot);
702 // Rust does not expect an outpointer. If the foreign fn
703 // does use an outpointer, then we will do a store of the
704 // value that the Rust fn returns.
705 return_alloca = None;
708 // Build up the arguments to the call to the rust function.
709 // Careful to adapt for cases where the native convention uses
710 // a pointer and Rust does not or vice versa.
711 for i in range(0, tys.fn_sig.inputs.len()) {
712 let rust_ty = *tys.fn_sig.inputs.get(i);
713 let llrust_ty = *tys.llsig.llarg_tys.get(i);
714 let rust_indirect = type_of::arg_is_indirect(ccx, rust_ty);
715 let llforeign_arg_ty = *tys.fn_ty.arg_tys.get(i);
716 let foreign_indirect = llforeign_arg_ty.is_indirect();
719 let foreign_index = next_foreign_arg(llforeign_arg_ty.pad.is_some());
720 let mut llforeign_arg = get_param(llwrapfn, foreign_index);
722 debug!("llforeign_arg {}{}: {}", "#",
723 i, ccx.tn.val_to_string(llforeign_arg));
724 debug!("rust_indirect = {}, foreign_indirect = {}",
725 rust_indirect, foreign_indirect);
727 // Ensure that the foreign argument is indirect (by
728 // pointer). It makes adapting types easier, since we can
729 // always just bitcast pointers.
730 if !foreign_indirect {
731 llforeign_arg = if ty::type_is_bool(rust_ty) {
732 let lltemp = builder.alloca(Type::bool(ccx), "");
733 builder.store(builder.zext(llforeign_arg, Type::bool(ccx)), lltemp);
736 let lltemp = builder.alloca(val_ty(llforeign_arg), "");
737 builder.store(llforeign_arg, lltemp);
742 // If the types in the ABI and the Rust types don't match,
743 // bitcast the llforeign_arg pointer so it matches the types
745 if llforeign_arg_ty.cast.is_some() {
746 assert!(!foreign_indirect);
747 llforeign_arg = builder.bitcast(llforeign_arg, llrust_ty.ptr_to());
750 let llrust_arg = if rust_indirect {
753 if ty::type_is_bool(rust_ty) {
754 let tmp = builder.load_range_assert(llforeign_arg, 0, 2, llvm::False);
755 builder.trunc(tmp, Type::i1(ccx))
757 builder.load(llforeign_arg)
761 debug!("llrust_arg {}{}: {}", "#",
762 i, ccx.tn.val_to_string(llrust_arg));
763 llrust_args.push(llrust_arg);
766 // Perform the call itself
767 debug!("calling llrustfn = {}, t = {}", ccx.tn.val_to_string(llrustfn), t.repr(ccx.tcx()));
768 let attributes = base::get_fn_llvm_attributes(ccx, t);
769 let llrust_ret_val = builder.call(llrustfn, llrust_args.as_slice(), Some(attributes));
771 // Get the return value where the foreign fn expects it.
772 let llforeign_ret_ty = match tys.fn_ty.ret_ty.cast {
774 None => tys.fn_ty.ret_ty.ty
776 match foreign_outptr {
777 None if !tys.ret_def => {
778 // Function returns `()` or `bot`, which in Rust is the LLVM
779 // type "{}" but in foreign ABIs is "Void".
783 None if rust_uses_outptr => {
784 // Rust uses an outpointer, but the foreign ABI does not. Load.
785 let llrust_outptr = return_alloca.unwrap();
786 let llforeign_outptr_casted =
787 builder.bitcast(llrust_outptr, llforeign_ret_ty.ptr_to());
788 let llforeign_retval = builder.load(llforeign_outptr_casted);
789 builder.ret(llforeign_retval);
792 None if llforeign_ret_ty != llrust_ret_ty => {
793 // Neither ABI uses an outpointer, but the types don't
794 // quite match. Must cast. Probably we should try and
795 // examine the types and use a concrete llvm cast, but
796 // right now we just use a temp memory location and
797 // bitcast the pointer, which is the same thing the
798 // old wrappers used to do.
799 let lltemp = builder.alloca(llforeign_ret_ty, "");
800 let lltemp_casted = builder.bitcast(lltemp, llrust_ret_ty.ptr_to());
801 builder.store(llrust_ret_val, lltemp_casted);
802 let llforeign_retval = builder.load(lltemp);
803 builder.ret(llforeign_retval);
807 // Neither ABI uses an outpointer, and the types
808 // match. Easy peasy.
809 builder.ret(llrust_ret_val);
812 Some(llforeign_outptr) if !rust_uses_outptr => {
813 // Foreign ABI requires an out pointer, but Rust doesn't.
814 // Store Rust return value.
815 let llforeign_outptr_casted =
816 builder.bitcast(llforeign_outptr, llrust_retptr_ty);
817 builder.store(llrust_ret_val, llforeign_outptr_casted);
822 // Both ABIs use outpointers. Easy peasy.
829 ///////////////////////////////////////////////////////////////////////////
830 // General ABI Support
832 // This code is kind of a confused mess and needs to be reworked given
833 // the massive simplifications that have occurred.
835 pub fn link_name(i: &ast::ForeignItem) -> InternedString {
836 match attr::first_attr_value_str_by_name(i.attrs.as_slice(), "link_name") {
837 Some(ln) => ln.clone(),
838 None => match weak_lang_items::link_name(i.attrs.as_slice()) {
840 None => token::get_ident(i.ident),
845 fn foreign_signature(ccx: &CrateContext, fn_sig: &ty::FnSig, arg_tys: &[ty::t])
848 * The ForeignSignature is the LLVM types of the arguments/return type
849 * of a function. Note that these LLVM types are not quite the same
850 * as the LLVM types would be for a native Rust function because foreign
851 * functions just plain ignore modes. They also don't pass aggregate
852 * values by pointer like we do.
855 let llarg_tys = arg_tys.iter().map(|&arg| arg_type_of(ccx, arg)).collect();
856 let llret_ty = type_of::arg_type_of(ccx, fn_sig.output);
858 llarg_tys: llarg_tys,
863 fn foreign_types_for_id(ccx: &CrateContext,
864 id: ast::NodeId) -> ForeignTypes {
865 foreign_types_for_fn_ty(ccx, ty::node_id_to_type(ccx.tcx(), id))
868 fn foreign_types_for_fn_ty(ccx: &CrateContext,
869 ty: ty::t) -> ForeignTypes {
870 let fn_sig = match ty::get(ty).sty {
871 ty::ty_bare_fn(ref fn_ty) => fn_ty.sig.clone(),
872 _ => ccx.sess().bug("foreign_types_for_fn_ty called on non-function type")
874 let llsig = foreign_signature(ccx, &fn_sig, fn_sig.inputs.as_slice());
875 let ret_def = !return_type_is_void(ccx, fn_sig.output);
876 let fn_ty = cabi::compute_abi_info(ccx,
877 llsig.llarg_tys.as_slice(),
880 debug!("foreign_types_for_fn_ty(\
886 ccx.tn.types_to_str(llsig.llarg_tys.as_slice()),
887 ccx.tn.type_to_string(llsig.llret_ty),
888 ccx.tn.types_to_str(fn_ty.arg_tys.iter().map(|t| t.ty).collect::<Vec<_>>().as_slice()),
889 ccx.tn.type_to_string(fn_ty.ret_ty.ty),
900 fn lltype_for_fn_from_foreign_types(ccx: &CrateContext, tys: &ForeignTypes) -> Type {
901 let mut llargument_tys = Vec::new();
903 let ret_ty = tys.fn_ty.ret_ty;
904 let llreturn_ty = if ret_ty.is_indirect() {
905 llargument_tys.push(ret_ty.ty.ptr_to());
914 for &arg_ty in tys.fn_ty.arg_tys.iter() {
915 if arg_ty.is_ignore() {
920 Some(ty) => llargument_tys.push(ty),
924 let llarg_ty = if arg_ty.is_indirect() {
933 llargument_tys.push(llarg_ty);
936 if tys.fn_sig.variadic {
937 Type::variadic_func(llargument_tys.as_slice(), &llreturn_ty)
939 Type::func(llargument_tys.as_slice(), &llreturn_ty)
943 pub fn lltype_for_foreign_fn(ccx: &CrateContext, ty: ty::t) -> Type {
944 lltype_for_fn_from_foreign_types(ccx, &foreign_types_for_fn_ty(ccx, ty))
947 fn add_argument_attributes(tys: &ForeignTypes,
949 let mut i = if tys.fn_ty.ret_ty.is_indirect() {
955 match tys.fn_ty.ret_ty.attr {
956 Some(attr) => unsafe {
957 llvm::LLVMAddFunctionAttribute(llfn, i as c_uint, attr as u64);
964 for &arg_ty in tys.fn_ty.arg_tys.iter() {
965 if arg_ty.is_ignore() {
969 if arg_ty.pad.is_some() { i += 1; }
972 Some(attr) => unsafe {
973 llvm::LLVMAddFunctionAttribute(llfn, i as c_uint, attr as u64);