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
::*;
31 use middle
::ty
::{self, Ty}
;
32 use middle
::subst
::Substs
;
37 use syntax
::abi
::{Cdecl, Aapcs, C, Win64, Abi}
;
38 use syntax
::abi
::{PlatformIntrinsic, RustIntrinsic, Rust, RustCall, Stdcall}
;
39 use syntax
::abi
::{Fastcall, Vectorcall, System}
;
41 use syntax
::codemap
::Span
;
42 use syntax
::parse
::token
::{InternedString, special_idents}
;
45 use rustc_front
::print
::pprust
;
48 ///////////////////////////////////////////////////////////////////////////
51 struct ForeignTypes
<'tcx
> {
52 /// Rust signature of the function
53 fn_sig
: ty
::FnSig
<'tcx
>,
55 /// Adapter object for handling native ABI rules (trust me, you
56 /// don't want to know)
59 /// LLVM types that will appear on the foreign function
63 struct LlvmSignature
{
64 // LLVM versions of the types of this function's arguments.
65 llarg_tys
: Vec
<Type
> ,
67 // LLVM version of the type that this function returns. Note that
68 // this *may not be* the declared return type of the foreign
69 // function, because the foreign function may opt to return via an
73 /// True if there is a return value (not bottom, not unit)
78 ///////////////////////////////////////////////////////////////////////////
79 // Calls to external functions
81 pub fn llvm_calling_convention(ccx
: &CrateContext
,
82 abi
: Abi
) -> CallConv
{
83 match ccx
.sess().target
.target
.adjust_abi(abi
) {
85 // Intrinsics are emitted at the call site
86 ccx
.sess().bug("asked to register intrinsic fn");
88 PlatformIntrinsic
=> {
89 // Intrinsics are emitted at the call site
90 ccx
.sess().bug("asked to register platform intrinsic fn");
94 // FIXME(#3678) Implement linking to foreign fns with Rust ABI
95 ccx
.sess().unimpl("foreign functions with Rust ABI");
99 // FIXME(#3678) Implement linking to foreign fns with Rust ABI
100 ccx
.sess().unimpl("foreign functions with RustCall ABI");
103 // It's the ABI's job to select this, not us.
104 System
=> ccx
.sess().bug("system abi should be selected elsewhere"),
106 Stdcall
=> llvm
::X86StdcallCallConv
,
107 Fastcall
=> llvm
::X86FastcallCallConv
,
108 Vectorcall
=> llvm
::X86_VectorCall
,
109 C
=> llvm
::CCallConv
,
110 Win64
=> llvm
::X86_64_Win64
,
112 // These API constants ought to be more specific...
113 Cdecl
=> llvm
::CCallConv
,
114 Aapcs
=> llvm
::CCallConv
,
118 pub fn register_static(ccx
: &CrateContext
,
119 foreign_item
: &hir
::ForeignItem
) -> ValueRef
{
120 let ty
= ccx
.tcx().node_id_to_type(foreign_item
.id
);
121 let llty
= type_of
::type_of(ccx
, ty
);
123 let ident
= link_name(foreign_item
);
124 match attr
::first_attr_value_str_by_name(&foreign_item
.attrs
,
126 // If this is a static with a linkage specified, then we need to handle
127 // it a little specially. The typesystem prevents things like &T and
128 // extern "C" fn() from being non-null, so we can't just declare a
129 // static and call it a day. Some linkages (like weak) will make it such
130 // that the static actually has a null value.
132 let linkage
= match llvm_linkage_by_name(&name
) {
133 Some(linkage
) => linkage
,
135 ccx
.sess().span_fatal(foreign_item
.span
,
136 "invalid linkage specified");
139 let llty2
= match ty
.sty
{
140 ty
::TyRawPtr(ref mt
) => type_of
::type_of(ccx
, mt
.ty
),
142 ccx
.sess().span_fatal(foreign_item
.span
,
143 "must have type `*T` or `*mut T`");
147 // Declare a symbol `foo` with the desired linkage.
148 let g1
= declare
::declare_global(ccx
, &ident
[..], llty2
);
149 llvm
::SetLinkage(g1
, linkage
);
151 // Declare an internal global `extern_with_linkage_foo` which
152 // is initialized with the address of `foo`. If `foo` is
153 // discarded during linking (for example, if `foo` has weak
154 // linkage and there are no definitions), then
155 // `extern_with_linkage_foo` will instead be initialized to
157 let mut real_name
= "_rust_extern_with_linkage_".to_string();
158 real_name
.push_str(&ident
);
159 let g2
= declare
::define_global(ccx
, &real_name
[..], llty
).unwrap_or_else(||{
160 ccx
.sess().span_fatal(foreign_item
.span
,
161 &format
!("symbol `{}` is already defined", ident
))
163 llvm
::SetLinkage(g2
, llvm
::InternalLinkage
);
164 llvm
::LLVMSetInitializer(g2
, g1
);
168 None
=> // Generate an external declaration.
169 declare
::declare_global(ccx
, &ident
[..], llty
),
173 // only use this for foreign function ABIs and glue, use `get_extern_rust_fn` for Rust functions
174 pub fn get_extern_fn(ccx
: &CrateContext
,
175 externs
: &mut ExternMap
,
181 match externs
.get(name
) {
182 Some(n
) => return *n
,
185 let f
= declare
::declare_fn(ccx
, name
, cc
, ty
, ty
::FnConverging(output
));
186 externs
.insert(name
.to_string(), f
);
190 /// Registers a foreign function found in a library. Just adds a LLVM global.
191 pub fn register_foreign_item_fn
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
192 abi
: Abi
, fty
: Ty
<'tcx
>,
194 attrs
: &[ast
::Attribute
])-> ValueRef
{
195 debug
!("register_foreign_item_fn(abi={:?}, \
202 let cc
= llvm_calling_convention(ccx
, abi
);
204 // Register the function as a C extern fn
205 let tys
= foreign_types_for_fn_ty(ccx
, fty
);
207 // Make sure the calling convention is right for variadic functions
208 // (should've been caught if not in typeck)
209 if tys
.fn_sig
.variadic
{
210 assert
!(cc
== llvm
::CCallConv
);
213 // Create the LLVM value for the C extern fn
214 let llfn_ty
= lltype_for_fn_from_foreign_types(ccx
, &tys
);
216 let llfn
= get_extern_fn(ccx
, &mut *ccx
.externs().borrow_mut(), name
, cc
, llfn_ty
, fty
);
217 attributes
::unwind(llfn
, false);
218 add_argument_attributes(&tys
, llfn
);
219 attributes
::from_fn_attrs(ccx
, attrs
, llfn
);
223 /// Prepares a call to a native function. This requires adapting
224 /// from the Rust argument passing rules to the native rules.
228 /// - `callee_ty`: Rust type for the function we are calling
229 /// - `llfn`: the function pointer we are calling
230 /// - `llretptr`: where to store the return value of the function
231 /// - `llargs_rust`: a list of the argument values, prepared
232 /// as they would be if calling a Rust function
233 /// - `passed_arg_tys`: Rust type for the arguments. Normally we
234 /// can derive these from callee_ty but in the case of variadic
235 /// functions passed_arg_tys will include the Rust type of all
236 /// the arguments including the ones not specified in the fn's signature.
237 pub fn trans_native_call
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
241 llargs_rust
: &[ValueRef
],
242 passed_arg_tys
: Vec
<Ty
<'tcx
>>,
243 call_debug_loc
: DebugLoc
)
248 debug
!("trans_native_call(callee_ty={:?}, \
252 ccx
.tn().val_to_string(llfn
),
253 ccx
.tn().val_to_string(llretptr
));
255 let (fn_abi
, fn_sig
) = match callee_ty
.sty
{
256 ty
::TyBareFn(_
, ref fn_ty
) => (fn_ty
.abi
, &fn_ty
.sig
),
257 _
=> ccx
.sess().bug("trans_native_call called on non-function type")
259 let fn_sig
= ccx
.tcx().erase_late_bound_regions(fn_sig
);
260 let fn_sig
= infer
::normalize_associated_type(ccx
.tcx(), &fn_sig
);
261 let llsig
= foreign_signature(ccx
, &fn_sig
, &passed_arg_tys
[..]);
262 let fn_type
= cabi
::compute_abi_info(ccx
,
267 let arg_tys
: &[cabi
::ArgType
] = &fn_type
.arg_tys
;
269 let mut llargs_foreign
= Vec
::new();
271 // If the foreign ABI expects return value by pointer, supply the
272 // pointer that Rust gave us. Sometimes we have to bitcast
273 // because foreign fns return slightly different (but equivalent)
274 // views on the same type (e.g., i64 in place of {i32,i32}).
275 if fn_type
.ret_ty
.is_indirect() {
276 match fn_type
.ret_ty
.cast
{
279 BitCast(bcx
, llretptr
, ty
.ptr_to());
280 llargs_foreign
.push(llcastedretptr
);
283 llargs_foreign
.push(llretptr
);
289 for (i
, arg_ty
) in arg_tys
.iter().enumerate() {
290 let mut llarg_rust
= llargs_rust
[i
+ offset
];
292 if arg_ty
.is_ignore() {
296 // Does Rust pass this argument by pointer?
297 let rust_indirect
= type_of
::arg_is_indirect(ccx
, passed_arg_tys
[i
]);
299 debug
!("argument {}, llarg_rust={}, rust_indirect={}, arg_ty={}",
301 ccx
.tn().val_to_string(llarg_rust
),
303 ccx
.tn().type_to_string(arg_ty
.ty
));
305 // Ensure that we always have the Rust value indirectly,
306 // because it makes bitcasting easier.
308 let scratch
= base
::alloc_ty(bcx
, passed_arg_tys
[i
], "__arg");
309 if type_is_fat_ptr(ccx
.tcx(), passed_arg_tys
[i
]) {
310 Store(bcx
, llargs_rust
[i
+ offset
], expr
::get_dataptr(bcx
, scratch
));
311 Store(bcx
, llargs_rust
[i
+ offset
+ 1], expr
::get_meta(bcx
, scratch
));
314 base
::store_ty(bcx
, llarg_rust
, scratch
, passed_arg_tys
[i
]);
316 llarg_rust
= scratch
;
319 debug
!("llarg_rust={} (after indirection)",
320 ccx
.tn().val_to_string(llarg_rust
));
322 // Check whether we need to do any casting
324 Some(ty
) => llarg_rust
= BitCast(bcx
, llarg_rust
, ty
.ptr_to()),
328 debug
!("llarg_rust={} (after casting)",
329 ccx
.tn().val_to_string(llarg_rust
));
331 // Finally, load the value if needed for the foreign ABI
332 let foreign_indirect
= arg_ty
.is_indirect();
333 let llarg_foreign
= if foreign_indirect
{
336 if passed_arg_tys
[i
].is_bool() {
337 let val
= LoadRangeAssert(bcx
, llarg_rust
, 0, 2, llvm
::False
);
338 Trunc(bcx
, val
, Type
::i1(bcx
.ccx()))
340 Load(bcx
, llarg_rust
)
344 debug
!("argument {}, llarg_foreign={}",
345 i
, ccx
.tn().val_to_string(llarg_foreign
));
347 // fill padding with undef value
349 Some(ty
) => llargs_foreign
.push(C_undef(ty
)),
352 llargs_foreign
.push(llarg_foreign
);
355 let cc
= llvm_calling_convention(ccx
, fn_abi
);
357 // A function pointer is called without the declaration available, so we have to apply
358 // any attributes with ABI implications directly to the call instruction.
359 let mut attrs
= llvm
::AttrBuilder
::new();
361 // Add attributes that are always applicable, independent of the concrete foreign ABI
362 if fn_type
.ret_ty
.is_indirect() {
363 let llret_sz
= machine
::llsize_of_real(ccx
, fn_type
.ret_ty
.ty
);
365 // The outptr can be noalias and nocapture because it's entirely
366 // invisible to the program. We also know it's nonnull as well
367 // as how many bytes we can dereference
368 attrs
.arg(1, llvm
::Attribute
::NoAlias
)
369 .arg(1, llvm
::Attribute
::NoCapture
)
370 .arg(1, llvm
::DereferenceableAttribute(llret_sz
));
373 // Add attributes that depend on the concrete foreign ABI
374 let mut arg_idx
= if fn_type
.ret_ty
.is_indirect() { 1 }
else { 0 }
;
375 match fn_type
.ret_ty
.attr
{
376 Some(attr
) => { attrs.arg(arg_idx, attr); }
,
381 for arg_ty
in &fn_type
.arg_tys
{
382 if arg_ty
.is_ignore() {
386 if arg_ty
.pad
.is_some() { arg_idx += 1; }
388 if let Some(attr
) = arg_ty
.attr
{
389 attrs
.arg(arg_idx
, attr
);
395 let llforeign_retval
= CallWithConv(bcx
,
402 // If the function we just called does not use an outpointer,
403 // store the result into the rust outpointer. Cast the outpointer
404 // type to match because some ABIs will use a different type than
405 // the Rust type. e.g., a {u32,u32} struct could be returned as
407 if llsig
.ret_def
&& !fn_type
.ret_ty
.is_indirect() {
408 let llrust_ret_ty
= llsig
.llret_ty
;
409 let llforeign_ret_ty
= match fn_type
.ret_ty
.cast
{
411 None
=> fn_type
.ret_ty
.ty
414 debug
!("llretptr={}", ccx
.tn().val_to_string(llretptr
));
415 debug
!("llforeign_retval={}", ccx
.tn().val_to_string(llforeign_retval
));
416 debug
!("llrust_ret_ty={}", ccx
.tn().type_to_string(llrust_ret_ty
));
417 debug
!("llforeign_ret_ty={}", ccx
.tn().type_to_string(llforeign_ret_ty
));
419 if llrust_ret_ty
== llforeign_ret_ty
{
420 match fn_sig
.output
{
421 ty
::FnConverging(result_ty
) => {
422 base
::store_ty(bcx
, llforeign_retval
, llretptr
, result_ty
)
424 ty
::FnDiverging
=> {}
427 // The actual return type is a struct, but the ABI
428 // adaptation code has cast it into some scalar type. The
429 // code that follows is the only reliable way I have
430 // found to do a transform like i64 -> {i32,i32}.
431 // Basically we dump the data onto the stack then memcpy it.
433 // Other approaches I tried:
434 // - Casting rust ret pointer to the foreign type and using Store
435 // is (a) unsafe if size of foreign type > size of rust type and
436 // (b) runs afoul of strict aliasing rules, yielding invalid
437 // assembly under -O (specifically, the store gets removed).
438 // - Truncating foreign type to correct integral type and then
439 // bitcasting to the struct type yields invalid cast errors.
440 let llscratch
= base
::alloca(bcx
, llforeign_ret_ty
, "__cast");
441 base
::call_lifetime_start(bcx
, llscratch
);
442 Store(bcx
, llforeign_retval
, llscratch
);
443 let llscratch_i8
= BitCast(bcx
, llscratch
, Type
::i8(ccx
).ptr_to());
444 let llretptr_i8
= BitCast(bcx
, llretptr
, Type
::i8(ccx
).ptr_to());
445 let llrust_size
= machine
::llsize_of_store(ccx
, llrust_ret_ty
);
446 let llforeign_align
= machine
::llalign_of_min(ccx
, llforeign_ret_ty
);
447 let llrust_align
= machine
::llalign_of_min(ccx
, llrust_ret_ty
);
448 let llalign
= cmp
::min(llforeign_align
, llrust_align
);
449 debug
!("llrust_size={}", llrust_size
);
450 base
::call_memcpy(bcx
, llretptr_i8
, llscratch_i8
,
451 C_uint(ccx
, llrust_size
), llalign
as u32);
452 base
::call_lifetime_end(bcx
, llscratch
);
459 // feature gate SIMD types in FFI, since I (huonw) am not sure the
460 // ABIs are handled at all correctly.
461 fn gate_simd_ffi(tcx
: &ty
::ctxt
, decl
: &hir
::FnDecl
, ty
: &ty
::BareFnTy
) {
462 if !tcx
.sess
.features
.borrow().simd_ffi
{
463 let check
= |ast_ty
: &hir
::Ty
, ty
: ty
::Ty
| {
465 tcx
.sess
.struct_span_err(ast_ty
.span
,
466 &format
!("use of SIMD type `{}` in FFI is highly experimental and \
467 may result in invalid code",
468 pprust
::ty_to_string(ast_ty
)))
469 .fileline_help(ast_ty
.span
,
470 "add #![feature(simd_ffi)] to the crate attributes to enable")
475 for (input
, ty
) in decl
.inputs
.iter().zip(&sig
.inputs
) {
476 check(&*input
.ty
, *ty
)
478 if let hir
::Return(ref ty
) = decl
.output
{
479 check(&**ty
, sig
.output
.unwrap())
484 pub fn trans_foreign_mod(ccx
: &CrateContext
, foreign_mod
: &hir
::ForeignMod
) {
485 let _icx
= push_ctxt("foreign::trans_foreign_mod");
486 for foreign_item
in &foreign_mod
.items
{
487 let lname
= link_name(foreign_item
);
489 if let hir
::ForeignItemFn(ref decl
, _
) = foreign_item
.node
{
490 match foreign_mod
.abi
{
491 Rust
| RustIntrinsic
| PlatformIntrinsic
=> {}
493 let ty
= ccx
.tcx().node_id_to_type(foreign_item
.id
);
495 ty
::TyBareFn(_
, bft
) => gate_simd_ffi(ccx
.tcx(), &**decl
, bft
),
496 _
=> ccx
.tcx().sess
.span_bug(foreign_item
.span
,
497 "foreign fn's sty isn't a bare_fn_ty?")
500 register_foreign_item_fn(ccx
, abi
, ty
, &lname
, &foreign_item
.attrs
);
501 // Unlike for other items, we shouldn't call
502 // `base::update_linkage` here. Foreign items have
503 // special linkage requirements, which are handled
504 // inside `foreign::register_*`.
509 ccx
.item_symbols().borrow_mut().insert(foreign_item
.id
,
514 ///////////////////////////////////////////////////////////////////////////
515 // Rust functions with foreign ABIs
517 // These are normal Rust functions defined with foreign ABIs. For
518 // now, and perhaps forever, we translate these using a "layer of
519 // indirection". That is, given a Rust declaration like:
521 // extern "C" fn foo(i: u32) -> u32 { ... }
523 // we will generate a function like:
527 // foo0(&r, NULL, i);
532 // void foo0(uint32_t *r, void *env, uint32_t i) { ... }
534 // Here the (internal) `foo0` function follows the Rust ABI as normal,
535 // where the `foo` function follows the C ABI. We rely on LLVM to
536 // inline the one into the other. Of course we could just generate the
537 // correct code in the first place, but this is much simpler.
539 pub fn decl_rust_fn_with_foreign_abi
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
543 let tys
= foreign_types_for_fn_ty(ccx
, t
);
544 let llfn_ty
= lltype_for_fn_from_foreign_types(ccx
, &tys
);
545 let cconv
= match t
.sty
{
546 ty
::TyBareFn(_
, ref fn_ty
) => {
547 llvm_calling_convention(ccx
, fn_ty
.abi
)
549 _
=> panic
!("expected bare fn in decl_rust_fn_with_foreign_abi")
551 let llfn
= declare
::declare_fn(ccx
, name
, cconv
, llfn_ty
,
552 ty
::FnConverging(ccx
.tcx().mk_nil()));
553 add_argument_attributes(&tys
, llfn
);
554 debug
!("decl_rust_fn_with_foreign_abi(llfn_ty={}, llfn={})",
555 ccx
.tn().type_to_string(llfn_ty
), ccx
.tn().val_to_string(llfn
));
559 pub fn register_rust_fn_with_foreign_abi(ccx
: &CrateContext
,
562 node_id
: ast
::NodeId
)
564 let _icx
= push_ctxt("foreign::register_foreign_fn");
566 let t
= ccx
.tcx().node_id_to_type(node_id
);
567 let cconv
= match t
.sty
{
568 ty
::TyBareFn(_
, ref fn_ty
) => {
569 llvm_calling_convention(ccx
, fn_ty
.abi
)
571 _
=> panic
!("expected bare fn in register_rust_fn_with_foreign_abi")
573 let tys
= foreign_types_for_fn_ty(ccx
, t
);
574 let llfn_ty
= lltype_for_fn_from_foreign_types(ccx
, &tys
);
575 let llfn
= base
::register_fn_llvmty(ccx
, sp
, sym
, node_id
, cconv
, llfn_ty
);
576 add_argument_attributes(&tys
, llfn
);
577 debug
!("register_rust_fn_with_foreign_abi(node_id={}, llfn_ty={}, llfn={})",
578 node_id
, ccx
.tn().type_to_string(llfn_ty
), ccx
.tn().val_to_string(llfn
));
582 pub fn trans_rust_fn_with_foreign_abi
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
585 attrs
: &[ast
::Attribute
],
587 param_substs
: &'tcx Substs
<'tcx
>,
589 hash
: Option
<&str>) {
590 let _icx
= push_ctxt("foreign::build_foreign_fn");
592 let fnty
= ccx
.tcx().node_id_to_type(id
);
593 let mty
= monomorphize
::apply_param_substs(ccx
.tcx(), param_substs
, &fnty
);
594 let tys
= foreign_types_for_fn_ty(ccx
, mty
);
596 unsafe { // unsafe because we call LLVM operations
597 // Build up the Rust function (`foo0` above).
598 let llrustfn
= build_rust_fn(ccx
, decl
, body
, param_substs
, attrs
, id
, hash
);
600 // Build up the foreign wrapper (`foo` above).
601 return build_wrap_fn(ccx
, llrustfn
, llwrapfn
, &tys
, mty
);
604 fn build_rust_fn
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
607 param_substs
: &'tcx Substs
<'tcx
>,
608 attrs
: &[ast
::Attribute
],
613 let _icx
= push_ctxt("foreign::foreign::build_rust_fn");
615 let t
= tcx
.node_id_to_type(id
);
616 let t
= monomorphize
::apply_param_substs(tcx
, param_substs
, &t
);
619 tcx
.map
.def_path_from_id(id
)
621 .map(|e
| e
.data
.as_interned_str())
622 .chain(once(special_idents
::clownshoe_abi
.name
.as_str()));
623 let ps
= link
::mangle(path
, hash
);
625 // Compute the type that the function would have if it were just a
626 // normal Rust function. This will be the type of the wrappee fn.
628 ty
::TyBareFn(_
, ref f
) => {
629 assert
!(f
.abi
!= Rust
&& f
.abi
!= RustIntrinsic
&& f
.abi
!= PlatformIntrinsic
);
632 ccx
.sess().bug(&format
!("build_rust_fn: extern fn {} has ty {:?}, \
633 expected a bare fn ty",
634 ccx
.tcx().map
.path_to_string(id
),
639 debug
!("build_rust_fn: path={} id={} t={:?}",
640 ccx
.tcx().map
.path_to_string(id
),
643 let llfn
= declare
::define_internal_rust_fn(ccx
, &ps
, t
);
644 attributes
::from_fn_attrs(ccx
, attrs
, llfn
);
645 base
::trans_fn(ccx
, decl
, body
, llfn
, param_substs
, id
, attrs
);
649 unsafe fn build_wrap_fn
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
652 tys
: &ForeignTypes
<'tcx
>,
654 let _icx
= push_ctxt(
655 "foreign::trans_rust_fn_with_foreign_abi::build_wrap_fn");
657 debug
!("build_wrap_fn(llrustfn={}, llwrapfn={}, t={:?})",
658 ccx
.tn().val_to_string(llrustfn
),
659 ccx
.tn().val_to_string(llwrapfn
),
662 // Avoid all the Rust generation stuff and just generate raw
665 // We want to generate code like this:
669 // foo0(&r, NULL, i);
673 if llvm
::LLVMCountBasicBlocks(llwrapfn
) != 0 {
674 ccx
.sess().bug("wrapping a function inside non-empty wrapper, most likely cause is \
675 multiple functions being wrapped");
678 let ptr
= "the block\0".as_ptr();
679 let the_block
= llvm
::LLVMAppendBasicBlockInContext(ccx
.llcx(), llwrapfn
,
682 let builder
= ccx
.builder();
683 builder
.position_at_end(the_block
);
685 // Array for the arguments we will pass to the rust function.
686 let mut llrust_args
= Vec
::new();
687 let mut next_foreign_arg_counter
: c_uint
= 0;
688 let mut next_foreign_arg
= |pad
: bool
| -> c_uint
{
689 next_foreign_arg_counter
+= if pad
{
694 next_foreign_arg_counter
- 1
697 // If there is an out pointer on the foreign function
698 let foreign_outptr
= {
699 if tys
.fn_ty
.ret_ty
.is_indirect() {
700 Some(get_param(llwrapfn
, next_foreign_arg(false)))
706 let rustfn_ty
= Type
::from_ref(llvm
::LLVMTypeOf(llrustfn
)).element_type();
707 let mut rust_param_tys
= rustfn_ty
.func_params().into_iter();
708 // Push Rust return pointer, using null if it will be unused.
709 let rust_uses_outptr
= match tys
.fn_sig
.output
{
710 ty
::FnConverging(ret_ty
) => type_of
::return_uses_outptr(ccx
, ret_ty
),
711 ty
::FnDiverging
=> false
713 let return_alloca
: Option
<ValueRef
>;
714 let llrust_ret_ty
= if rust_uses_outptr
{
715 rust_param_tys
.next().expect("Missing return type!").element_type()
717 rustfn_ty
.return_type()
719 if rust_uses_outptr
{
720 // Rust expects to use an outpointer. If the foreign fn
721 // also uses an outpointer, we can reuse it, but the types
722 // may vary, so cast first to the Rust type. If the
723 // foreign fn does NOT use an outpointer, we will have to
724 // alloca some scratch space on the stack.
725 match foreign_outptr
{
726 Some(llforeign_outptr
) => {
727 debug
!("out pointer, foreign={}",
728 ccx
.tn().val_to_string(llforeign_outptr
));
730 builder
.bitcast(llforeign_outptr
, llrust_ret_ty
.ptr_to());
731 debug
!("out pointer, foreign={} (casted)",
732 ccx
.tn().val_to_string(llrust_retptr
));
733 llrust_args
.push(llrust_retptr
);
734 return_alloca
= None
;
738 let slot
= builder
.alloca(llrust_ret_ty
, "return_alloca");
739 debug
!("out pointer, \
743 ccx
.tn().val_to_string(slot
),
744 ccx
.tn().type_to_string(llrust_ret_ty
),
746 llrust_args
.push(slot
);
747 return_alloca
= Some(slot
);
751 // Rust does not expect an outpointer. If the foreign fn
752 // does use an outpointer, then we will do a store of the
753 // value that the Rust fn returns.
754 return_alloca
= None
;
757 // Build up the arguments to the call to the rust function.
758 // Careful to adapt for cases where the native convention uses
759 // a pointer and Rust does not or vice versa.
760 for i
in 0..tys
.fn_sig
.inputs
.len() {
761 let rust_ty
= tys
.fn_sig
.inputs
[i
];
762 let rust_indirect
= type_of
::arg_is_indirect(ccx
, rust_ty
);
763 let llty
= rust_param_tys
.next().expect("Not enough parameter types!");
764 let llrust_ty
= if rust_indirect
{
769 let llforeign_arg_ty
= tys
.fn_ty
.arg_tys
[i
];
770 let foreign_indirect
= llforeign_arg_ty
.is_indirect();
772 if llforeign_arg_ty
.is_ignore() {
773 debug
!("skipping ignored arg #{}", i
);
774 llrust_args
.push(C_undef(llrust_ty
));
779 let foreign_index
= next_foreign_arg(llforeign_arg_ty
.pad
.is_some());
780 let mut llforeign_arg
= get_param(llwrapfn
, foreign_index
);
782 debug
!("llforeign_arg {}{}: {}", "#",
783 i
, ccx
.tn().val_to_string(llforeign_arg
));
784 debug
!("rust_indirect = {}, foreign_indirect = {}",
785 rust_indirect
, foreign_indirect
);
787 // Ensure that the foreign argument is indirect (by
788 // pointer). It makes adapting types easier, since we can
789 // always just bitcast pointers.
790 if !foreign_indirect
{
791 llforeign_arg
= if rust_ty
.is_bool() {
792 let lltemp
= builder
.alloca(Type
::bool(ccx
), "");
793 builder
.store(builder
.zext(llforeign_arg
, Type
::bool(ccx
)), lltemp
);
796 let lltemp
= builder
.alloca(val_ty(llforeign_arg
), "");
797 builder
.store(llforeign_arg
, lltemp
);
802 // If the types in the ABI and the Rust types don't match,
803 // bitcast the llforeign_arg pointer so it matches the types
805 if llforeign_arg_ty
.cast
.is_some() && !type_is_fat_ptr(ccx
.tcx(), rust_ty
){
806 assert
!(!foreign_indirect
);
807 llforeign_arg
= builder
.bitcast(llforeign_arg
, llrust_ty
.ptr_to());
810 let llrust_arg
= if rust_indirect
|| type_is_fat_ptr(ccx
.tcx(), rust_ty
) {
813 if rust_ty
.is_bool() {
814 let tmp
= builder
.load_range_assert(llforeign_arg
, 0, 2, llvm
::False
);
815 builder
.trunc(tmp
, Type
::i1(ccx
))
816 } else if type_of
::type_of(ccx
, rust_ty
).is_aggregate() {
817 // We want to pass small aggregates as immediate values, but using an aggregate
818 // LLVM type for this leads to bad optimizations, so its arg type is an
819 // appropriately sized integer and we have to convert it
820 let tmp
= builder
.bitcast(llforeign_arg
,
821 type_of
::arg_type_of(ccx
, rust_ty
).ptr_to());
822 let load
= builder
.load(tmp
);
823 llvm
::LLVMSetAlignment(load
, type_of
::align_of(ccx
, rust_ty
));
826 builder
.load(llforeign_arg
)
830 debug
!("llrust_arg {}{}: {}", "#",
831 i
, ccx
.tn().val_to_string(llrust_arg
));
832 if type_is_fat_ptr(ccx
.tcx(), rust_ty
) {
833 let next_llrust_ty
= rust_param_tys
.next().expect("Not enough parameter types!");
834 llrust_args
.push(builder
.load(builder
.bitcast(builder
.struct_gep(
835 llrust_arg
, abi
::FAT_PTR_ADDR
), llrust_ty
.ptr_to())));
836 llrust_args
.push(builder
.load(builder
.bitcast(builder
.struct_gep(
837 llrust_arg
, abi
::FAT_PTR_EXTRA
), next_llrust_ty
.ptr_to())));
839 llrust_args
.push(llrust_arg
);
843 // Perform the call itself
844 debug
!("calling llrustfn = {}, t = {:?}",
845 ccx
.tn().val_to_string(llrustfn
), t
);
846 let attributes
= attributes
::from_fn_type(ccx
, t
);
847 let llrust_ret_val
= builder
.call(llrustfn
, &llrust_args
, Some(attributes
));
849 // Get the return value where the foreign fn expects it.
850 let llforeign_ret_ty
= match tys
.fn_ty
.ret_ty
.cast
{
852 None
=> tys
.fn_ty
.ret_ty
.ty
854 match foreign_outptr
{
855 None
if !tys
.llsig
.ret_def
=> {
856 // Function returns `()` or `bot`, which in Rust is the LLVM
857 // type "{}" but in foreign ABIs is "Void".
861 None
if rust_uses_outptr
=> {
862 // Rust uses an outpointer, but the foreign ABI does not. Load.
863 let llrust_outptr
= return_alloca
.unwrap();
864 let llforeign_outptr_casted
=
865 builder
.bitcast(llrust_outptr
, llforeign_ret_ty
.ptr_to());
866 let llforeign_retval
= builder
.load(llforeign_outptr_casted
);
867 builder
.ret(llforeign_retval
);
870 None
if llforeign_ret_ty
!= llrust_ret_ty
=> {
871 // Neither ABI uses an outpointer, but the types don't
872 // quite match. Must cast. Probably we should try and
873 // examine the types and use a concrete llvm cast, but
874 // right now we just use a temp memory location and
875 // bitcast the pointer, which is the same thing the
876 // old wrappers used to do.
877 let lltemp
= builder
.alloca(llforeign_ret_ty
, "");
878 let lltemp_casted
= builder
.bitcast(lltemp
, llrust_ret_ty
.ptr_to());
879 builder
.store(llrust_ret_val
, lltemp_casted
);
880 let llforeign_retval
= builder
.load(lltemp
);
881 builder
.ret(llforeign_retval
);
885 // Neither ABI uses an outpointer, and the types
886 // match. Easy peasy.
887 builder
.ret(llrust_ret_val
);
890 Some(llforeign_outptr
) if !rust_uses_outptr
=> {
891 // Foreign ABI requires an out pointer, but Rust doesn't.
892 // Store Rust return value.
893 let llforeign_outptr_casted
=
894 builder
.bitcast(llforeign_outptr
, llrust_ret_ty
.ptr_to());
895 builder
.store(llrust_ret_val
, llforeign_outptr_casted
);
900 // Both ABIs use outpointers. Easy peasy.
907 ///////////////////////////////////////////////////////////////////////////
908 // General ABI Support
910 // This code is kind of a confused mess and needs to be reworked given
911 // the massive simplifications that have occurred.
913 pub fn link_name(i
: &hir
::ForeignItem
) -> InternedString
{
914 match attr
::first_attr_value_str_by_name(&i
.attrs
, "link_name") {
915 Some(ln
) => ln
.clone(),
916 None
=> match weak_lang_items
::link_name(&i
.attrs
) {
918 None
=> i
.name
.as_str(),
923 /// The ForeignSignature is the LLVM types of the arguments/return type of a function. Note that
924 /// these LLVM types are not quite the same as the LLVM types would be for a native Rust function
925 /// because foreign functions just plain ignore modes. They also don't pass aggregate values by
926 /// pointer like we do.
927 fn foreign_signature
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
928 fn_sig
: &ty
::FnSig
<'tcx
>,
929 arg_tys
: &[Ty
<'tcx
>])
931 let llarg_tys
= arg_tys
.iter().map(|&arg
| foreign_arg_type_of(ccx
, arg
)).collect();
932 let (llret_ty
, ret_def
) = match fn_sig
.output
{
933 ty
::FnConverging(ret_ty
) =>
934 (type_of
::foreign_arg_type_of(ccx
, ret_ty
), !return_type_is_void(ccx
, ret_ty
)),
936 (Type
::nil(ccx
), false)
939 llarg_tys
: llarg_tys
,
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 fn_sig
= infer
::normalize_associated_type(ccx
.tcx(), &fn_sig
);
953 let llsig
= foreign_signature(ccx
, &fn_sig
, &fn_sig
.inputs
);
954 let fn_ty
= cabi
::compute_abi_info(ccx
,
958 debug
!("foreign_types_for_fn_ty(\
964 ccx
.tn().types_to_str(&llsig
.llarg_tys
),
965 ccx
.tn().type_to_string(llsig
.llret_ty
),
966 ccx
.tn().types_to_str(&fn_ty
.arg_tys
.iter().map(|t
| t
.ty
).collect
::<Vec
<_
>>()),
967 ccx
.tn().type_to_string(fn_ty
.ret_ty
.ty
),
977 fn lltype_for_fn_from_foreign_types(ccx
: &CrateContext
, tys
: &ForeignTypes
) -> Type
{
978 let mut llargument_tys
= Vec
::new();
980 let ret_ty
= tys
.fn_ty
.ret_ty
;
981 let llreturn_ty
= if ret_ty
.is_indirect() {
982 llargument_tys
.push(ret_ty
.ty
.ptr_to());
991 for &arg_ty
in &tys
.fn_ty
.arg_tys
{
992 if arg_ty
.is_ignore() {
997 Some(ty
) => llargument_tys
.push(ty
),
1001 let llarg_ty
= if arg_ty
.is_indirect() {
1010 llargument_tys
.push(llarg_ty
);
1013 if tys
.fn_sig
.variadic
{
1014 Type
::variadic_func(&llargument_tys
, &llreturn_ty
)
1016 Type
::func(&llargument_tys
[..], &llreturn_ty
)
1020 pub fn lltype_for_foreign_fn
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
1021 ty
: Ty
<'tcx
>) -> Type
{
1022 lltype_for_fn_from_foreign_types(ccx
, &foreign_types_for_fn_ty(ccx
, ty
))
1025 fn add_argument_attributes(tys
: &ForeignTypes
,
1027 let mut i
= if tys
.fn_ty
.ret_ty
.is_indirect() {
1033 match tys
.fn_ty
.ret_ty
.attr
{
1034 Some(attr
) => unsafe {
1035 llvm
::LLVMAddFunctionAttribute(llfn
, i
as c_uint
, attr
.bits() as u64);
1042 for &arg_ty
in &tys
.fn_ty
.arg_tys
{
1043 if arg_ty
.is_ignore() {
1047 if arg_ty
.pad
.is_some() { i += 1; }
1050 Some(attr
) => unsafe {
1051 llvm
::LLVMAddFunctionAttribute(llfn
, i
as c_uint
, attr
.bits() as u64);