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};
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,
108 pub fn register_foreign_item_fn(ccx: @CrateContext, abis: AbiSet,
109 foreign_item: @ast::ForeignItem) -> ValueRef {
111 * Registers a foreign function found in a library.
112 * Just adds a LLVM global.
115 debug!("register_foreign_item_fn(abis={}, \
117 foreign_item.id={})",
119 ccx.tcx.map.path_to_str(foreign_item.id),
122 let cc = match llvm_calling_convention(ccx, abis) {
125 ccx.sess.span_fatal(foreign_item.span,
126 format!("ABI `{}` has no suitable calling convention \
127 for target architecture",
128 abis.user_string(ccx.tcx)));
132 // Register the function as a C extern fn
133 let lname = link_name(foreign_item);
134 let tys = foreign_types_for_id(ccx, foreign_item.id);
136 // Make sure the calling convention is right for variadic functions
137 // (should've been caught if not in typeck)
138 if tys.fn_sig.variadic {
139 assert!(cc == lib::llvm::CCallConv);
142 // Create the LLVM value for the C extern fn
143 let llfn_ty = lltype_for_fn_from_foreign_types(&tys);
147 let mut externs = ccx.externs.borrow_mut();
148 llfn = base::get_extern_fn(externs.get(),
155 add_argument_attributes(&tys, llfn);
160 pub fn trans_native_call<'a>(
165 llargs_rust: &[ValueRef],
166 passed_arg_tys: Vec<ty::t> )
169 * Prepares a call to a native function. This requires adapting
170 * from the Rust argument passing rules to the native rules.
174 * - `callee_ty`: Rust type for the function we are calling
175 * - `llfn`: the function pointer we are calling
176 * - `llretptr`: where to store the return value of the function
177 * - `llargs_rust`: a list of the argument values, prepared
178 * as they would be if calling a Rust function
179 * - `passed_arg_tys`: Rust type for the arguments. Normally we
180 * can derive these from callee_ty but in the case of variadic
181 * functions passed_arg_tys will include the Rust type of all
182 * the arguments including the ones not specified in the fn's signature.
188 debug!("trans_native_call(callee_ty={}, \
192 ccx.tn.val_to_str(llfn),
193 ccx.tn.val_to_str(llretptr));
195 let (fn_abis, fn_sig) = match ty::get(callee_ty).sty {
196 ty::ty_bare_fn(ref fn_ty) => (fn_ty.abis, fn_ty.sig.clone()),
197 _ => ccx.sess.bug("trans_native_call called on non-function type")
199 let llsig = foreign_signature(ccx, &fn_sig, passed_arg_tys);
200 let ret_def = !return_type_is_void(bcx.ccx(), fn_sig.output);
201 let fn_type = cabi::compute_abi_info(ccx,
206 let arg_tys: &[cabi::ArgType] = fn_type.arg_tys;
208 let mut llargs_foreign = Vec::new();
210 // If the foreign ABI expects return value by pointer, supply the
211 // pointer that Rust gave us. Sometimes we have to bitcast
212 // because foreign fns return slightly different (but equivalent)
213 // views on the same type (e.g., i64 in place of {i32,i32}).
214 if fn_type.ret_ty.is_indirect() {
215 match fn_type.ret_ty.cast {
218 BitCast(bcx, llretptr, ty.ptr_to());
219 llargs_foreign.push(llcastedretptr);
222 llargs_foreign.push(llretptr);
227 for (i, &llarg_rust) in llargs_rust.iter().enumerate() {
228 let mut llarg_rust = llarg_rust;
230 // Does Rust pass this argument by pointer?
231 let rust_indirect = type_of::arg_is_indirect(ccx, passed_arg_tys[i]);
233 debug!("argument {}, llarg_rust={}, rust_indirect={}, arg_ty={}",
235 ccx.tn.val_to_str(llarg_rust),
237 ccx.tn.type_to_str(arg_tys[i].ty));
239 // Ensure that we always have the Rust value indirectly,
240 // because it makes bitcasting easier.
242 let scratch = base::alloca(bcx, type_of::type_of(ccx, passed_arg_tys[i]), "__arg");
243 Store(bcx, llarg_rust, scratch);
244 llarg_rust = scratch;
247 debug!("llarg_rust={} (after indirection)",
248 ccx.tn.val_to_str(llarg_rust));
250 // Check whether we need to do any casting
251 match arg_tys[i].cast {
252 Some(ty) => llarg_rust = BitCast(bcx, llarg_rust, ty.ptr_to()),
256 debug!("llarg_rust={} (after casting)",
257 ccx.tn.val_to_str(llarg_rust));
259 // Finally, load the value if needed for the foreign ABI
260 let foreign_indirect = arg_tys[i].is_indirect();
261 let llarg_foreign = if foreign_indirect {
264 Load(bcx, llarg_rust)
267 debug!("argument {}, llarg_foreign={}",
268 i, ccx.tn.val_to_str(llarg_foreign));
270 // fill padding with undef value
271 match arg_tys[i].pad {
272 Some(ty) => llargs_foreign.push(C_undef(ty)),
275 llargs_foreign.push(llarg_foreign);
278 let cc = match llvm_calling_convention(ccx, fn_abis) {
281 // FIXME(#8357) We really ought to report a span here
283 format!("ABI string `{}` has no suitable ABI \
284 for target architecture",
285 fn_abis.user_string(ccx.tcx)));
289 // A function pointer is called without the declaration available, so we have to apply
290 // any attributes with ABI implications directly to the call instruction. Right now, the
291 // only attribute we need to worry about is `sret`.
292 let sret_attr = if fn_type.ret_ty.is_indirect() {
293 Some((1, StructRetAttribute))
297 let attrs = sret_attr.as_slice();
298 let llforeign_retval = CallWithConv(bcx, llfn, llargs_foreign, cc, attrs);
300 // If the function we just called does not use an outpointer,
301 // store the result into the rust outpointer. Cast the outpointer
302 // type to match because some ABIs will use a different type than
303 // the Rust type. e.g., a {u32,u32} struct could be returned as
305 if ret_def && !fn_type.ret_ty.is_indirect() {
306 let llrust_ret_ty = llsig.llret_ty;
307 let llforeign_ret_ty = match fn_type.ret_ty.cast {
309 None => fn_type.ret_ty.ty
312 debug!("llretptr={}", ccx.tn.val_to_str(llretptr));
313 debug!("llforeign_retval={}", ccx.tn.val_to_str(llforeign_retval));
314 debug!("llrust_ret_ty={}", ccx.tn.type_to_str(llrust_ret_ty));
315 debug!("llforeign_ret_ty={}", ccx.tn.type_to_str(llforeign_ret_ty));
317 if llrust_ret_ty == llforeign_ret_ty {
318 Store(bcx, llforeign_retval, llretptr);
320 // The actual return type is a struct, but the ABI
321 // adaptation code has cast it into some scalar type. The
322 // code that follows is the only reliable way I have
323 // found to do a transform like i64 -> {i32,i32}.
324 // Basically we dump the data onto the stack then memcpy it.
326 // Other approaches I tried:
327 // - Casting rust ret pointer to the foreign type and using Store
328 // is (a) unsafe if size of foreign type > size of rust type and
329 // (b) runs afoul of strict aliasing rules, yielding invalid
330 // assembly under -O (specifically, the store gets removed).
331 // - Truncating foreign type to correct integral type and then
332 // bitcasting to the struct type yields invalid cast errors.
333 let llscratch = base::alloca(bcx, llforeign_ret_ty, "__cast");
334 Store(bcx, llforeign_retval, llscratch);
335 let llscratch_i8 = BitCast(bcx, llscratch, Type::i8().ptr_to());
336 let llretptr_i8 = BitCast(bcx, llretptr, Type::i8().ptr_to());
337 let llrust_size = machine::llsize_of_store(ccx, llrust_ret_ty);
338 let llforeign_align = machine::llalign_of_min(ccx, llforeign_ret_ty);
339 let llrust_align = machine::llalign_of_min(ccx, llrust_ret_ty);
340 let llalign = cmp::min(llforeign_align, llrust_align);
341 debug!("llrust_size={:?}", llrust_size);
342 base::call_memcpy(bcx, llretptr_i8, llscratch_i8,
343 C_uint(ccx, llrust_size as uint), llalign as u32);
350 pub fn trans_foreign_mod(ccx: @CrateContext, foreign_mod: &ast::ForeignMod) {
351 let _icx = push_ctxt("foreign::trans_foreign_mod");
352 for &foreign_item in foreign_mod.items.iter() {
353 match foreign_item.node {
354 ast::ForeignItemFn(..) => {
355 let abis = foreign_mod.abis;
356 if !(abis.is_rust() || abis.is_intrinsic()) {
357 register_foreign_item_fn(ccx, abis, foreign_item);
363 let lname = link_name(foreign_item);
364 let mut item_symbols = ccx.item_symbols.borrow_mut();
365 item_symbols.get().insert(foreign_item.id, lname.get().to_owned());
369 ///////////////////////////////////////////////////////////////////////////
370 // Rust functions with foreign ABIs
372 // These are normal Rust functions defined with foreign ABIs. For
373 // now, and perhaps forever, we translate these using a "layer of
374 // indirection". That is, given a Rust declaration like:
376 // extern "C" fn foo(i: u32) -> u32 { ... }
378 // we will generate a function like:
382 // foo0(&r, NULL, i);
387 // void foo0(uint32_t *r, void *env, uint32_t i) { ... }
389 // Here the (internal) `foo0` function follows the Rust ABI as normal,
390 // where the `foo` function follows the C ABI. We rely on LLVM to
391 // inline the one into the other. Of course we could just generate the
392 // correct code in the first place, but this is much simpler.
394 pub fn register_rust_fn_with_foreign_abi(ccx: @CrateContext,
397 node_id: ast::NodeId)
399 let _icx = push_ctxt("foreign::register_foreign_fn");
401 let tys = foreign_types_for_id(ccx, node_id);
402 let llfn_ty = lltype_for_fn_from_foreign_types(&tys);
403 let t = ty::node_id_to_type(ccx.tcx, node_id);
404 let (cconv, output) = match ty::get(t).sty {
405 ty::ty_bare_fn(ref fn_ty) => {
406 let c = llvm_calling_convention(ccx, fn_ty.abis);
407 (c.unwrap_or(lib::llvm::CCallConv), fn_ty.sig.output)
409 _ => fail!("expected bare fn in register_rust_fn_with_foreign_abi")
411 let llfn = base::register_fn_llvmty(ccx, sp, sym, node_id, cconv, llfn_ty, output);
412 add_argument_attributes(&tys, llfn);
413 debug!("register_rust_fn_with_foreign_abi(node_id={:?}, llfn_ty={}, llfn={})",
414 node_id, ccx.tn.type_to_str(llfn_ty), ccx.tn.val_to_str(llfn));
418 pub fn trans_rust_fn_with_foreign_abi(ccx: @CrateContext,
421 attrs: &[ast::Attribute],
424 let _icx = push_ctxt("foreign::build_foreign_fn");
425 let tys = foreign_types_for_id(ccx, id);
427 unsafe { // unsafe because we call LLVM operations
428 // Build up the Rust function (`foo0` above).
429 let llrustfn = build_rust_fn(ccx, decl, body, attrs, id);
431 // Build up the foreign wrapper (`foo` above).
432 return build_wrap_fn(ccx, llrustfn, llwrapfn, &tys);
435 fn build_rust_fn(ccx: @CrateContext,
438 attrs: &[ast::Attribute],
441 let _icx = push_ctxt("foreign::foreign::build_rust_fn");
443 let t = ty::node_id_to_type(tcx, id);
445 let ps = ccx.tcx.map.with_path(id, |path| {
446 let abi = Some(ast_map::PathName(special_idents::clownshoe_abi.name));
447 link::mangle(path.chain(abi.move_iter()), None, None)
450 // Compute the type that the function would have if it were just a
451 // normal Rust function. This will be the type of the wrappee fn.
452 let f = match ty::get(t).sty {
453 ty::ty_bare_fn(ref f) => {
454 assert!(!f.abis.is_rust() && !f.abis.is_intrinsic());
458 ccx.sess.bug(format!("build_rust_fn: extern fn {} has ty {}, \
459 expected a bare fn ty",
460 ccx.tcx.map.path_to_str(id),
465 debug!("build_rust_fn: path={} id={} t={}",
466 ccx.tcx.map.path_to_str(id),
469 let llfn = base::decl_internal_rust_fn(ccx, false, f.sig.inputs, f.sig.output, ps);
470 base::set_llvm_fn_attrs(attrs, llfn);
471 base::trans_fn(ccx, decl, body, llfn, None, id, []);
475 unsafe fn build_wrap_fn(ccx: @CrateContext,
478 tys: &ForeignTypes) {
479 let _icx = push_ctxt(
480 "foreign::trans_rust_fn_with_foreign_abi::build_wrap_fn");
483 debug!("build_wrap_fn(llrustfn={}, llwrapfn={})",
484 ccx.tn.val_to_str(llrustfn),
485 ccx.tn.val_to_str(llwrapfn));
487 // Avoid all the Rust generation stuff and just generate raw
490 // We want to generate code like this:
494 // foo0(&r, NULL, i);
499 "the block".with_c_str(
500 |s| llvm::LLVMAppendBasicBlockInContext(ccx.llcx, llwrapfn, s));
502 let builder = ccx.builder.b;
503 llvm::LLVMPositionBuilderAtEnd(builder, the_block);
505 // Array for the arguments we will pass to the rust function.
506 let mut llrust_args = Vec::new();
507 let mut next_foreign_arg_counter: c_uint = 0;
508 let next_foreign_arg: |pad: bool| -> c_uint = |pad: bool| {
509 next_foreign_arg_counter += if pad {
514 next_foreign_arg_counter - 1
517 // If there is an out pointer on the foreign function
518 let foreign_outptr = {
519 if tys.fn_ty.ret_ty.is_indirect() {
520 Some(llvm::LLVMGetParam(llwrapfn, next_foreign_arg(false)))
526 // Push Rust return pointer, using null if it will be unused.
527 let rust_uses_outptr =
528 type_of::return_uses_outptr(ccx, tys.fn_sig.output);
529 let return_alloca: Option<ValueRef>;
530 let llrust_ret_ty = tys.llsig.llret_ty;
531 let llrust_retptr_ty = llrust_ret_ty.ptr_to();
532 if rust_uses_outptr {
533 // Rust expects to use an outpointer. If the foreign fn
534 // also uses an outpointer, we can reuse it, but the types
535 // may vary, so cast first to the Rust type. If the
536 // foreign fn does NOT use an outpointer, we will have to
537 // alloca some scratch space on the stack.
538 match foreign_outptr {
539 Some(llforeign_outptr) => {
540 debug!("out pointer, foreign={}",
541 ccx.tn.val_to_str(llforeign_outptr));
543 llvm::LLVMBuildBitCast(builder,
545 llrust_ret_ty.ptr_to().to_ref(),
547 debug!("out pointer, foreign={} (casted)",
548 ccx.tn.val_to_str(llrust_retptr));
549 llrust_args.push(llrust_retptr);
550 return_alloca = None;
555 "return_alloca".with_c_str(
556 |s| llvm::LLVMBuildAlloca(builder,
557 llrust_ret_ty.to_ref(),
560 debug!("out pointer, \
564 ccx.tn.val_to_str(slot),
565 ccx.tn.type_to_str(llrust_ret_ty),
566 tys.fn_sig.output.repr(tcx));
567 llrust_args.push(slot);
568 return_alloca = Some(slot);
572 // Rust does not expect an outpointer. If the foreign fn
573 // does use an outpointer, then we will do a store of the
574 // value that the Rust fn returns.
575 return_alloca = None;
578 // Build up the arguments to the call to the rust function.
579 // Careful to adapt for cases where the native convention uses
580 // a pointer and Rust does not or vice versa.
581 for i in range(0, tys.fn_sig.inputs.len()) {
582 let rust_ty = tys.fn_sig.inputs[i];
583 let llrust_ty = tys.llsig.llarg_tys[i];
584 let rust_indirect = type_of::arg_is_indirect(ccx, rust_ty);
585 let llforeign_arg_ty = tys.fn_ty.arg_tys[i];
586 let foreign_indirect = llforeign_arg_ty.is_indirect();
589 let foreign_index = next_foreign_arg(llforeign_arg_ty.pad.is_some());
590 let mut llforeign_arg = llvm::LLVMGetParam(llwrapfn, foreign_index);
592 debug!("llforeign_arg \\#{}: {}",
593 i, ccx.tn.val_to_str(llforeign_arg));
594 debug!("rust_indirect = {}, foreign_indirect = {}",
595 rust_indirect, foreign_indirect);
597 // Ensure that the foreign argument is indirect (by
598 // pointer). It makes adapting types easier, since we can
599 // always just bitcast pointers.
600 if !foreign_indirect {
602 llvm::LLVMBuildAlloca(
603 builder, val_ty(llforeign_arg).to_ref(), noname());
604 llvm::LLVMBuildStore(
605 builder, llforeign_arg, lltemp);
606 llforeign_arg = lltemp;
609 // If the types in the ABI and the Rust types don't match,
610 // bitcast the llforeign_arg pointer so it matches the types
612 if llforeign_arg_ty.cast.is_some() {
613 assert!(!foreign_indirect);
614 llforeign_arg = llvm::LLVMBuildBitCast(
615 builder, llforeign_arg,
616 llrust_ty.ptr_to().to_ref(), noname());
619 let llrust_arg = if rust_indirect {
622 llvm::LLVMBuildLoad(builder, llforeign_arg, noname())
625 debug!("llrust_arg \\#{}: {}",
626 i, ccx.tn.val_to_str(llrust_arg));
627 llrust_args.push(llrust_arg);
630 // Perform the call itself
631 debug!("calling llrustfn = {}", ccx.tn.val_to_str(llrustfn));
632 let llrust_ret_val = llvm::LLVMBuildCall(builder, llrustfn, llrust_args.as_ptr(),
633 llrust_args.len() as c_uint, noname());
635 // Get the return value where the foreign fn expects it.
636 let llforeign_ret_ty = match tys.fn_ty.ret_ty.cast {
638 None => tys.fn_ty.ret_ty.ty
640 match foreign_outptr {
641 None if !tys.ret_def => {
642 // Function returns `()` or `bot`, which in Rust is the LLVM
643 // type "{}" but in foreign ABIs is "Void".
644 llvm::LLVMBuildRetVoid(builder);
647 None if rust_uses_outptr => {
648 // Rust uses an outpointer, but the foreign ABI does not. Load.
649 let llrust_outptr = return_alloca.unwrap();
650 let llforeign_outptr_casted =
651 llvm::LLVMBuildBitCast(builder,
653 llforeign_ret_ty.ptr_to().to_ref(),
655 let llforeign_retval =
656 llvm::LLVMBuildLoad(builder, llforeign_outptr_casted, noname());
657 llvm::LLVMBuildRet(builder, llforeign_retval);
660 None if llforeign_ret_ty != llrust_ret_ty => {
661 // Neither ABI uses an outpointer, but the types don't
662 // quite match. Must cast. Probably we should try and
663 // examine the types and use a concrete llvm cast, but
664 // right now we just use a temp memory location and
665 // bitcast the pointer, which is the same thing the
666 // old wrappers used to do.
668 llvm::LLVMBuildAlloca(
669 builder, llforeign_ret_ty.to_ref(), noname());
671 llvm::LLVMBuildBitCast(builder,
673 llrust_ret_ty.ptr_to().to_ref(),
675 llvm::LLVMBuildStore(
676 builder, llrust_ret_val, lltemp_casted);
677 let llforeign_retval =
678 llvm::LLVMBuildLoad(builder, lltemp, noname());
679 llvm::LLVMBuildRet(builder, llforeign_retval);
683 // Neither ABI uses an outpointer, and the types
684 // match. Easy peasy.
685 llvm::LLVMBuildRet(builder, llrust_ret_val);
688 Some(llforeign_outptr) if !rust_uses_outptr => {
689 // Foreign ABI requires an out pointer, but Rust doesn't.
690 // Store Rust return value.
691 let llforeign_outptr_casted =
692 llvm::LLVMBuildBitCast(builder,
694 llrust_retptr_ty.to_ref(),
696 llvm::LLVMBuildStore(
697 builder, llrust_ret_val, llforeign_outptr_casted);
698 llvm::LLVMBuildRetVoid(builder);
702 // Both ABIs use outpointers. Easy peasy.
703 llvm::LLVMBuildRetVoid(builder);
709 ///////////////////////////////////////////////////////////////////////////
710 // General ABI Support
712 // This code is kind of a confused mess and needs to be reworked given
713 // the massive simplifications that have occurred.
715 pub fn link_name(i: @ast::ForeignItem) -> InternedString {
716 match attr::first_attr_value_str_by_name(i.attrs.as_slice(),
718 None => token::get_ident(i.ident),
719 Some(ln) => ln.clone(),
723 fn foreign_signature(ccx: &CrateContext, fn_sig: &ty::FnSig, arg_tys: &[ty::t])
726 * The ForeignSignature is the LLVM types of the arguments/return type
727 * of a function. Note that these LLVM types are not quite the same
728 * as the LLVM types would be for a native Rust function because foreign
729 * functions just plain ignore modes. They also don't pass aggregate
730 * values by pointer like we do.
733 let llarg_tys = arg_tys.map(|&arg| type_of(ccx, arg));
734 let llret_ty = type_of::type_of(ccx, fn_sig.output);
736 llarg_tys: llarg_tys,
738 sret: type_of::return_uses_outptr(ccx, fn_sig.output),
742 fn foreign_types_for_id(ccx: &CrateContext,
743 id: ast::NodeId) -> ForeignTypes {
744 foreign_types_for_fn_ty(ccx, ty::node_id_to_type(ccx.tcx, id))
747 fn foreign_types_for_fn_ty(ccx: &CrateContext,
748 ty: ty::t) -> ForeignTypes {
749 let fn_sig = match ty::get(ty).sty {
750 ty::ty_bare_fn(ref fn_ty) => fn_ty.sig.clone(),
751 _ => ccx.sess.bug("foreign_types_for_fn_ty called on non-function type")
753 let llsig = foreign_signature(ccx, &fn_sig, fn_sig.inputs);
754 let ret_def = !return_type_is_void(ccx, fn_sig.output);
755 let fn_ty = cabi::compute_abi_info(ccx,
759 debug!("foreign_types_for_fn_ty(\
765 ccx.tn.types_to_str(llsig.llarg_tys),
766 ccx.tn.type_to_str(llsig.llret_ty),
767 ccx.tn.types_to_str(fn_ty.arg_tys.map(|t| t.ty)),
768 ccx.tn.type_to_str(fn_ty.ret_ty.ty),
779 fn lltype_for_fn_from_foreign_types(tys: &ForeignTypes) -> Type {
780 let mut llargument_tys = Vec::new();
782 let ret_ty = tys.fn_ty.ret_ty;
783 let llreturn_ty = if ret_ty.is_indirect() {
784 llargument_tys.push(ret_ty.ty.ptr_to());
793 for &arg_ty in tys.fn_ty.arg_tys.iter() {
796 Some(ty) => llargument_tys.push(ty),
800 let llarg_ty = if arg_ty.is_indirect() {
809 llargument_tys.push(llarg_ty);
812 if tys.fn_sig.variadic {
813 Type::variadic_func(llargument_tys, &llreturn_ty)
815 Type::func(llargument_tys, &llreturn_ty)
819 pub fn lltype_for_foreign_fn(ccx: &CrateContext, ty: ty::t) -> Type {
820 let fn_types = foreign_types_for_fn_ty(ccx, ty);
821 lltype_for_fn_from_foreign_types(&fn_types)
824 fn add_argument_attributes(tys: &ForeignTypes,
828 if tys.fn_ty.ret_ty.is_indirect() {
829 match tys.fn_ty.ret_ty.attr {
831 let llarg = get_param(llfn, i);
833 llvm::LLVMAddAttribute(llarg, attr as c_uint);
842 for &arg_ty in tys.fn_ty.arg_tys.iter() {
844 if arg_ty.pad.is_some() { i += 1; }
848 let llarg = get_param(llfn, i);
850 llvm::LLVMAddAttribute(llarg, attr as c_uint);