]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans/foreign.rs
Merge pull request #20510 from tshepang/patch-6
[rust.git] / src / librustc_trans / trans / foreign.rs
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.
4 //
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.
10
11
12 use back::{link};
13 use llvm::{ValueRef, CallConv, get_param};
14 use llvm;
15 use middle::weak_lang_items;
16 use trans::base::{llvm_linkage_by_name, push_ctxt};
17 use trans::base;
18 use trans::build::*;
19 use trans::cabi;
20 use trans::common::*;
21 use trans::machine;
22 use trans::monomorphize;
23 use trans::type_::Type;
24 use trans::type_of::*;
25 use trans::type_of;
26 use middle::ty::{self, Ty};
27 use middle::subst::{Substs};
28 use std::cmp;
29 use std::c_str::ToCStr;
30 use libc::c_uint;
31 use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi};
32 use syntax::abi::{RustIntrinsic, Rust, RustCall, Stdcall, Fastcall, System};
33 use syntax::codemap::Span;
34 use syntax::parse::token::{InternedString, special_idents};
35 use syntax::parse::token;
36 use syntax::{ast};
37 use syntax::{attr, ast_map};
38 use util::ppaux::Repr;
39
40 ///////////////////////////////////////////////////////////////////////////
41 // Type definitions
42
43 struct ForeignTypes<'tcx> {
44     /// Rust signature of the function
45     fn_sig: ty::PolyFnSig<'tcx>,
46
47     /// Adapter object for handling native ABI rules (trust me, you
48     /// don't want to know)
49     fn_ty: cabi::FnType,
50
51     /// LLVM types that will appear on the foreign function
52     llsig: LlvmSignature,
53 }
54
55 struct LlvmSignature {
56     // LLVM versions of the types of this function's arguments.
57     llarg_tys: Vec<Type> ,
58
59     // LLVM version of the type that this function returns.  Note that
60     // this *may not be* the declared return type of the foreign
61     // function, because the foreign function may opt to return via an
62     // out pointer.
63     llret_ty: Type,
64
65     /// True if there is a return value (not bottom, not unit)
66     ret_def: bool,
67 }
68
69
70 ///////////////////////////////////////////////////////////////////////////
71 // Calls to external functions
72
73 pub fn llvm_calling_convention(ccx: &CrateContext,
74                                abi: Abi) -> CallConv {
75     match ccx.sess().target.target.adjust_abi(abi) {
76         RustIntrinsic => {
77             // Intrinsics are emitted at the call site
78             ccx.sess().bug("asked to register intrinsic fn");
79         }
80
81         Rust => {
82             // FIXME(#3678) Implement linking to foreign fns with Rust ABI
83             ccx.sess().unimpl("foreign functions with Rust ABI");
84         }
85
86         RustCall => {
87             // FIXME(#3678) Implement linking to foreign fns with Rust ABI
88             ccx.sess().unimpl("foreign functions with RustCall ABI");
89         }
90
91         // It's the ABI's job to select this, not us.
92         System => ccx.sess().bug("system abi should be selected elsewhere"),
93
94         Stdcall => llvm::X86StdcallCallConv,
95         Fastcall => llvm::X86FastcallCallConv,
96         C => llvm::CCallConv,
97         Win64 => llvm::X86_64_Win64,
98
99         // These API constants ought to be more specific...
100         Cdecl => llvm::CCallConv,
101         Aapcs => llvm::CCallConv,
102     }
103 }
104
105 pub fn register_static(ccx: &CrateContext,
106                        foreign_item: &ast::ForeignItem) -> ValueRef {
107     let ty = ty::node_id_to_type(ccx.tcx(), foreign_item.id);
108     let llty = type_of::type_of(ccx, ty);
109
110     let ident = link_name(foreign_item);
111     match attr::first_attr_value_str_by_name(foreign_item.attrs[],
112                                              "linkage") {
113         // If this is a static with a linkage specified, then we need to handle
114         // it a little specially. The typesystem prevents things like &T and
115         // extern "C" fn() from being non-null, so we can't just declare a
116         // static and call it a day. Some linkages (like weak) will make it such
117         // that the static actually has a null value.
118         Some(name) => {
119             let linkage = match llvm_linkage_by_name(name.get()) {
120                 Some(linkage) => linkage,
121                 None => {
122                     ccx.sess().span_fatal(foreign_item.span,
123                                           "invalid linkage specified");
124                 }
125             };
126             let llty2 = match ty.sty {
127                 ty::ty_ptr(ref mt) => type_of::type_of(ccx, mt.ty),
128                 _ => {
129                     ccx.sess().span_fatal(foreign_item.span,
130                                           "must have type `*T` or `*mut T`");
131                 }
132             };
133             unsafe {
134                 // Declare a symbol `foo` with the desired linkage.
135                 let g1 = ident.get().with_c_str(|buf| {
136                     llvm::LLVMAddGlobal(ccx.llmod(), llty2.to_ref(), buf)
137                 });
138                 llvm::SetLinkage(g1, linkage);
139
140                 // Declare an internal global `extern_with_linkage_foo` which
141                 // is initialized with the address of `foo`.  If `foo` is
142                 // discarded during linking (for example, if `foo` has weak
143                 // linkage and there are no definitions), then
144                 // `extern_with_linkage_foo` will instead be initialized to
145                 // zero.
146                 let mut real_name = "_rust_extern_with_linkage_".to_string();
147                 real_name.push_str(ident.get());
148                 let g2 = real_name.with_c_str(|buf| {
149                     llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf)
150                 });
151                 llvm::SetLinkage(g2, llvm::InternalLinkage);
152                 llvm::LLVMSetInitializer(g2, g1);
153                 g2
154             }
155         }
156         None => unsafe {
157             // Generate an external declaration.
158             ident.get().with_c_str(|buf| {
159                 llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf)
160             })
161         }
162     }
163 }
164
165 /// Registers a foreign function found in a library. Just adds a LLVM global.
166 pub fn register_foreign_item_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
167                                           abi: Abi, fty: Ty<'tcx>,
168                                           name: &str) -> ValueRef {
169     debug!("register_foreign_item_fn(abi={}, \
170             ty={}, \
171             name={})",
172            abi.repr(ccx.tcx()),
173            fty.repr(ccx.tcx()),
174            name);
175
176     let cc = llvm_calling_convention(ccx, abi);
177
178     // Register the function as a C extern fn
179     let tys = foreign_types_for_fn_ty(ccx, fty);
180
181     // Make sure the calling convention is right for variadic functions
182     // (should've been caught if not in typeck)
183     if tys.fn_sig.0.variadic {
184         assert!(cc == llvm::CCallConv);
185     }
186
187     // Create the LLVM value for the C extern fn
188     let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
189
190     let llfn = base::get_extern_fn(ccx,
191                                    &mut *ccx.externs().borrow_mut(),
192                                    name,
193                                    cc,
194                                    llfn_ty,
195                                    fty);
196     add_argument_attributes(&tys, llfn);
197
198     llfn
199 }
200
201 /// Prepares a call to a native function. This requires adapting
202 /// from the Rust argument passing rules to the native rules.
203 ///
204 /// # Parameters
205 ///
206 /// - `callee_ty`: Rust type for the function we are calling
207 /// - `llfn`: the function pointer we are calling
208 /// - `llretptr`: where to store the return value of the function
209 /// - `llargs_rust`: a list of the argument values, prepared
210 ///   as they would be if calling a Rust function
211 /// - `passed_arg_tys`: Rust type for the arguments. Normally we
212 ///   can derive these from callee_ty but in the case of variadic
213 ///   functions passed_arg_tys will include the Rust type of all
214 ///   the arguments including the ones not specified in the fn's signature.
215 pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
216                                      callee_ty: Ty<'tcx>,
217                                      llfn: ValueRef,
218                                      llretptr: ValueRef,
219                                      llargs_rust: &[ValueRef],
220                                      passed_arg_tys: Vec<Ty<'tcx>>)
221                                      -> Block<'blk, 'tcx> {
222     let ccx = bcx.ccx();
223     let tcx = bcx.tcx();
224
225     debug!("trans_native_call(callee_ty={}, \
226             llfn={}, \
227             llretptr={})",
228            callee_ty.repr(tcx),
229            ccx.tn().val_to_string(llfn),
230            ccx.tn().val_to_string(llretptr));
231
232     let (fn_abi, fn_sig) = match callee_ty.sty {
233         ty::ty_bare_fn(_, ref fn_ty) => (fn_ty.abi, fn_ty.sig.clone()),
234         _ => ccx.sess().bug("trans_native_call called on non-function type")
235     };
236     let llsig = foreign_signature(ccx, &fn_sig, passed_arg_tys[]);
237     let fn_type = cabi::compute_abi_info(ccx,
238                                          llsig.llarg_tys[],
239                                          llsig.llret_ty,
240                                          llsig.ret_def);
241
242     let arg_tys: &[cabi::ArgType] = fn_type.arg_tys[];
243
244     let mut llargs_foreign = Vec::new();
245
246     // If the foreign ABI expects return value by pointer, supply the
247     // pointer that Rust gave us. Sometimes we have to bitcast
248     // because foreign fns return slightly different (but equivalent)
249     // views on the same type (e.g., i64 in place of {i32,i32}).
250     if fn_type.ret_ty.is_indirect() {
251         match fn_type.ret_ty.cast {
252             Some(ty) => {
253                 let llcastedretptr =
254                     BitCast(bcx, llretptr, ty.ptr_to());
255                 llargs_foreign.push(llcastedretptr);
256             }
257             None => {
258                 llargs_foreign.push(llretptr);
259             }
260         }
261     }
262
263     for (i, &llarg_rust) in llargs_rust.iter().enumerate() {
264         let mut llarg_rust = llarg_rust;
265
266         if arg_tys[i].is_ignore() {
267             continue;
268         }
269
270         // Does Rust pass this argument by pointer?
271         let rust_indirect = type_of::arg_is_indirect(ccx, passed_arg_tys[i]);
272
273         debug!("argument {}, llarg_rust={}, rust_indirect={}, arg_ty={}",
274                i,
275                ccx.tn().val_to_string(llarg_rust),
276                rust_indirect,
277                ccx.tn().type_to_string(arg_tys[i].ty));
278
279         // Ensure that we always have the Rust value indirectly,
280         // because it makes bitcasting easier.
281         if !rust_indirect {
282             let scratch =
283                 base::alloca(bcx,
284                              type_of::type_of(ccx, passed_arg_tys[i]),
285                              "__arg");
286             base::store_ty(bcx, llarg_rust, scratch, passed_arg_tys[i]);
287             llarg_rust = scratch;
288         }
289
290         debug!("llarg_rust={} (after indirection)",
291                ccx.tn().val_to_string(llarg_rust));
292
293         // Check whether we need to do any casting
294         match arg_tys[i].cast {
295             Some(ty) => llarg_rust = BitCast(bcx, llarg_rust, ty.ptr_to()),
296             None => ()
297         }
298
299         debug!("llarg_rust={} (after casting)",
300                ccx.tn().val_to_string(llarg_rust));
301
302         // Finally, load the value if needed for the foreign ABI
303         let foreign_indirect = arg_tys[i].is_indirect();
304         let llarg_foreign = if foreign_indirect {
305             llarg_rust
306         } else {
307             if ty::type_is_bool(passed_arg_tys[i]) {
308                 let val = LoadRangeAssert(bcx, llarg_rust, 0, 2, llvm::False);
309                 Trunc(bcx, val, Type::i1(bcx.ccx()))
310             } else {
311                 Load(bcx, llarg_rust)
312             }
313         };
314
315         debug!("argument {}, llarg_foreign={}",
316                i, ccx.tn().val_to_string(llarg_foreign));
317
318         // fill padding with undef value
319         match arg_tys[i].pad {
320             Some(ty) => llargs_foreign.push(C_undef(ty)),
321             None => ()
322         }
323         llargs_foreign.push(llarg_foreign);
324     }
325
326     let cc = llvm_calling_convention(ccx, fn_abi);
327
328     // A function pointer is called without the declaration available, so we have to apply
329     // any attributes with ABI implications directly to the call instruction.
330     let mut attrs = llvm::AttrBuilder::new();
331
332     // Add attributes that are always applicable, independent of the concrete foreign ABI
333     if fn_type.ret_ty.is_indirect() {
334         let llret_sz = machine::llsize_of_real(ccx, fn_type.ret_ty.ty);
335
336         // The outptr can be noalias and nocapture because it's entirely
337         // invisible to the program. We also know it's nonnull as well
338         // as how many bytes we can dereference
339         attrs.arg(1, llvm::NoAliasAttribute)
340              .arg(1, llvm::NoCaptureAttribute)
341              .arg(1, llvm::DereferenceableAttribute(llret_sz));
342     };
343
344     // Add attributes that depend on the concrete foreign ABI
345     let mut arg_idx = if fn_type.ret_ty.is_indirect() { 1 } else { 0 };
346     match fn_type.ret_ty.attr {
347         Some(attr) => { attrs.arg(arg_idx, attr); },
348         _ => ()
349     }
350
351     arg_idx += 1;
352     for arg_ty in fn_type.arg_tys.iter() {
353         if arg_ty.is_ignore() {
354             continue;
355         }
356         // skip padding
357         if arg_ty.pad.is_some() { arg_idx += 1; }
358
359         if let Some(attr) = arg_ty.attr {
360             attrs.arg(arg_idx, attr);
361         }
362
363         arg_idx += 1;
364     }
365
366     let llforeign_retval = CallWithConv(bcx,
367                                         llfn,
368                                         llargs_foreign[],
369                                         cc,
370                                         Some(attrs));
371
372     // If the function we just called does not use an outpointer,
373     // store the result into the rust outpointer. Cast the outpointer
374     // type to match because some ABIs will use a different type than
375     // the Rust type. e.g., a {u32,u32} struct could be returned as
376     // u64.
377     if llsig.ret_def && !fn_type.ret_ty.is_indirect() {
378         let llrust_ret_ty = llsig.llret_ty;
379         let llforeign_ret_ty = match fn_type.ret_ty.cast {
380             Some(ty) => ty,
381             None => fn_type.ret_ty.ty
382         };
383
384         debug!("llretptr={}", ccx.tn().val_to_string(llretptr));
385         debug!("llforeign_retval={}", ccx.tn().val_to_string(llforeign_retval));
386         debug!("llrust_ret_ty={}", ccx.tn().type_to_string(llrust_ret_ty));
387         debug!("llforeign_ret_ty={}", ccx.tn().type_to_string(llforeign_ret_ty));
388
389         if llrust_ret_ty == llforeign_ret_ty {
390             match fn_sig.0.output {
391                 ty::FnConverging(result_ty) => {
392                     base::store_ty(bcx, llforeign_retval, llretptr, result_ty)
393                 }
394                 ty::FnDiverging => {}
395             }
396         } else {
397             // The actual return type is a struct, but the ABI
398             // adaptation code has cast it into some scalar type.  The
399             // code that follows is the only reliable way I have
400             // found to do a transform like i64 -> {i32,i32}.
401             // Basically we dump the data onto the stack then memcpy it.
402             //
403             // Other approaches I tried:
404             // - Casting rust ret pointer to the foreign type and using Store
405             //   is (a) unsafe if size of foreign type > size of rust type and
406             //   (b) runs afoul of strict aliasing rules, yielding invalid
407             //   assembly under -O (specifically, the store gets removed).
408             // - Truncating foreign type to correct integral type and then
409             //   bitcasting to the struct type yields invalid cast errors.
410             let llscratch = base::alloca(bcx, llforeign_ret_ty, "__cast");
411             Store(bcx, llforeign_retval, llscratch);
412             let llscratch_i8 = BitCast(bcx, llscratch, Type::i8(ccx).ptr_to());
413             let llretptr_i8 = BitCast(bcx, llretptr, Type::i8(ccx).ptr_to());
414             let llrust_size = machine::llsize_of_store(ccx, llrust_ret_ty);
415             let llforeign_align = machine::llalign_of_min(ccx, llforeign_ret_ty);
416             let llrust_align = machine::llalign_of_min(ccx, llrust_ret_ty);
417             let llalign = cmp::min(llforeign_align, llrust_align);
418             debug!("llrust_size={}", llrust_size);
419             base::call_memcpy(bcx, llretptr_i8, llscratch_i8,
420                               C_uint(ccx, llrust_size), llalign as u32);
421         }
422     }
423
424     return bcx;
425 }
426
427 pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &ast::ForeignMod) {
428     let _icx = push_ctxt("foreign::trans_foreign_mod");
429     for foreign_item in foreign_mod.items.iter() {
430         let lname = link_name(&**foreign_item);
431
432         if let ast::ForeignItemFn(..) = foreign_item.node {
433             match foreign_mod.abi {
434                 Rust | RustIntrinsic => {}
435                 abi => {
436                     let ty = ty::node_id_to_type(ccx.tcx(), foreign_item.id);
437                     register_foreign_item_fn(ccx, abi, ty,
438                                              lname.get()[]);
439                     // Unlike for other items, we shouldn't call
440                     // `base::update_linkage` here.  Foreign items have
441                     // special linkage requirements, which are handled
442                     // inside `foreign::register_*`.
443                 }
444             }
445         }
446
447         ccx.item_symbols().borrow_mut().insert(foreign_item.id,
448                                              lname.get().to_string());
449     }
450 }
451
452 ///////////////////////////////////////////////////////////////////////////
453 // Rust functions with foreign ABIs
454 //
455 // These are normal Rust functions defined with foreign ABIs.  For
456 // now, and perhaps forever, we translate these using a "layer of
457 // indirection". That is, given a Rust declaration like:
458 //
459 //     extern "C" fn foo(i: u32) -> u32 { ... }
460 //
461 // we will generate a function like:
462 //
463 //     S foo(T i) {
464 //         S r;
465 //         foo0(&r, NULL, i);
466 //         return r;
467 //     }
468 //
469 //     #[inline_always]
470 //     void foo0(uint32_t *r, void *env, uint32_t i) { ... }
471 //
472 // Here the (internal) `foo0` function follows the Rust ABI as normal,
473 // where the `foo` function follows the C ABI. We rely on LLVM to
474 // inline the one into the other. Of course we could just generate the
475 // correct code in the first place, but this is much simpler.
476
477 pub fn decl_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
478                                                t: Ty<'tcx>,
479                                                name: &str)
480                                                -> ValueRef {
481     let tys = foreign_types_for_fn_ty(ccx, t);
482     let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
483     let cconv = match t.sty {
484         ty::ty_bare_fn(_, ref fn_ty) => {
485             llvm_calling_convention(ccx, fn_ty.abi)
486         }
487         _ => panic!("expected bare fn in decl_rust_fn_with_foreign_abi")
488     };
489     let llfn = base::decl_fn(ccx, name, cconv, llfn_ty, ty::FnConverging(ty::mk_nil(ccx.tcx())));
490     add_argument_attributes(&tys, llfn);
491     debug!("decl_rust_fn_with_foreign_abi(llfn_ty={}, llfn={})",
492            ccx.tn().type_to_string(llfn_ty), ccx.tn().val_to_string(llfn));
493     llfn
494 }
495
496 pub fn register_rust_fn_with_foreign_abi(ccx: &CrateContext,
497                                          sp: Span,
498                                          sym: String,
499                                          node_id: ast::NodeId)
500                                          -> ValueRef {
501     let _icx = push_ctxt("foreign::register_foreign_fn");
502
503     let tys = foreign_types_for_id(ccx, node_id);
504     let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
505     let t = ty::node_id_to_type(ccx.tcx(), node_id);
506     let cconv = match t.sty {
507         ty::ty_bare_fn(_, ref fn_ty) => {
508             llvm_calling_convention(ccx, fn_ty.abi)
509         }
510         _ => panic!("expected bare fn in register_rust_fn_with_foreign_abi")
511     };
512     let llfn = base::register_fn_llvmty(ccx, sp, sym, node_id, cconv, llfn_ty);
513     add_argument_attributes(&tys, llfn);
514     debug!("register_rust_fn_with_foreign_abi(node_id={}, llfn_ty={}, llfn={})",
515            node_id, ccx.tn().type_to_string(llfn_ty), ccx.tn().val_to_string(llfn));
516     llfn
517 }
518
519 pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
520                                                 decl: &ast::FnDecl,
521                                                 body: &ast::Block,
522                                                 attrs: &[ast::Attribute],
523                                                 llwrapfn: ValueRef,
524                                                 param_substs: &Substs<'tcx>,
525                                                 id: ast::NodeId,
526                                                 hash: Option<&str>) {
527     let _icx = push_ctxt("foreign::build_foreign_fn");
528
529     let fnty = ty::node_id_to_type(ccx.tcx(), id);
530     let mty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &fnty);
531     let tys = foreign_types_for_fn_ty(ccx, mty);
532
533     unsafe { // unsafe because we call LLVM operations
534         // Build up the Rust function (`foo0` above).
535         let llrustfn = build_rust_fn(ccx, decl, body, param_substs, attrs, id, hash);
536
537         // Build up the foreign wrapper (`foo` above).
538         return build_wrap_fn(ccx, llrustfn, llwrapfn, &tys, mty);
539     }
540
541     fn build_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
542                                decl: &ast::FnDecl,
543                                body: &ast::Block,
544                                param_substs: &Substs<'tcx>,
545                                attrs: &[ast::Attribute],
546                                id: ast::NodeId,
547                                hash: Option<&str>)
548                                -> ValueRef
549     {
550         let _icx = push_ctxt("foreign::foreign::build_rust_fn");
551         let tcx = ccx.tcx();
552         let t = ty::node_id_to_type(tcx, id);
553         let t = monomorphize::apply_param_substs(tcx, param_substs, &t);
554
555         let ps = ccx.tcx().map.with_path(id, |path| {
556             let abi = Some(ast_map::PathName(special_idents::clownshoe_abi.name));
557             link::mangle(path.chain(abi.into_iter()), hash)
558         });
559
560         // Compute the type that the function would have if it were just a
561         // normal Rust function. This will be the type of the wrappee fn.
562         match t.sty {
563             ty::ty_bare_fn(_, ref f) => {
564                 assert!(f.abi != Rust && f.abi != RustIntrinsic);
565             }
566             _ => {
567                 ccx.sess().bug(format!("build_rust_fn: extern fn {} has ty {}, \
568                                         expected a bare fn ty",
569                                        ccx.tcx().map.path_to_string(id),
570                                        t.repr(tcx))[]);
571             }
572         };
573
574         debug!("build_rust_fn: path={} id={} t={}",
575                ccx.tcx().map.path_to_string(id),
576                id, t.repr(tcx));
577
578         let llfn = base::decl_internal_rust_fn(ccx, t, ps[]);
579         base::set_llvm_fn_attrs(ccx, attrs, llfn);
580         base::trans_fn(ccx, decl, body, llfn, param_substs, id, &[]);
581         llfn
582     }
583
584     unsafe fn build_wrap_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
585                                       llrustfn: ValueRef,
586                                       llwrapfn: ValueRef,
587                                       tys: &ForeignTypes<'tcx>,
588                                       t: Ty<'tcx>) {
589         let _icx = push_ctxt(
590             "foreign::trans_rust_fn_with_foreign_abi::build_wrap_fn");
591         let tcx = ccx.tcx();
592
593         debug!("build_wrap_fn(llrustfn={}, llwrapfn={}, t={})",
594                ccx.tn().val_to_string(llrustfn),
595                ccx.tn().val_to_string(llwrapfn),
596                t.repr(ccx.tcx()));
597
598         // Avoid all the Rust generation stuff and just generate raw
599         // LLVM here.
600         //
601         // We want to generate code like this:
602         //
603         //     S foo(T i) {
604         //         S r;
605         //         foo0(&r, NULL, i);
606         //         return r;
607         //     }
608
609         let the_block =
610             "the block".with_c_str(
611                 |s| llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llwrapfn, s));
612
613         let builder = ccx.builder();
614         builder.position_at_end(the_block);
615
616         // Array for the arguments we will pass to the rust function.
617         let mut llrust_args = Vec::new();
618         let mut next_foreign_arg_counter: c_uint = 0;
619         let mut next_foreign_arg = |&mut : pad: bool| -> c_uint {
620             next_foreign_arg_counter += if pad {
621                 2
622             } else {
623                 1
624             };
625             next_foreign_arg_counter - 1
626         };
627
628         // If there is an out pointer on the foreign function
629         let foreign_outptr = {
630             if tys.fn_ty.ret_ty.is_indirect() {
631                 Some(get_param(llwrapfn, next_foreign_arg(false)))
632             } else {
633                 None
634             }
635         };
636
637         // Push Rust return pointer, using null if it will be unused.
638         let rust_uses_outptr = match tys.fn_sig.0.output {
639             ty::FnConverging(ret_ty) => type_of::return_uses_outptr(ccx, ret_ty),
640             ty::FnDiverging => false
641         };
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_string(llforeign_outptr));
655                     let llrust_retptr =
656                         builder.bitcast(llforeign_outptr, llrust_retptr_ty);
657                     debug!("out pointer, foreign={} (casted)",
658                            ccx.tn().val_to_string(llrust_retptr));
659                     llrust_args.push(llrust_retptr);
660                     return_alloca = None;
661                 }
662
663                 None => {
664                     let slot = builder.alloca(llrust_ret_ty, "return_alloca");
665                     debug!("out pointer, \
666                             allocad={}, \
667                             llrust_ret_ty={}, \
668                             return_ty={}",
669                            ccx.tn().val_to_string(slot),
670                            ccx.tn().type_to_string(llrust_ret_ty),
671                            tys.fn_sig.0.output.repr(tcx));
672                     llrust_args.push(slot);
673                     return_alloca = Some(slot);
674                 }
675             }
676         } else {
677             // Rust does not expect an outpointer. If the foreign fn
678             // does use an outpointer, then we will do a store of the
679             // value that the Rust fn returns.
680             return_alloca = None;
681         };
682
683         // Build up the arguments to the call to the rust function.
684         // Careful to adapt for cases where the native convention uses
685         // a pointer and Rust does not or vice versa.
686         for i in range(0, tys.fn_sig.0.inputs.len()) {
687             let rust_ty = tys.fn_sig.0.inputs[i];
688             let llrust_ty = tys.llsig.llarg_tys[i];
689             let rust_indirect = type_of::arg_is_indirect(ccx, rust_ty);
690             let llforeign_arg_ty = tys.fn_ty.arg_tys[i];
691             let foreign_indirect = llforeign_arg_ty.is_indirect();
692
693             if llforeign_arg_ty.is_ignore() {
694                 debug!("skipping ignored arg #{}", i);
695                 llrust_args.push(C_undef(llrust_ty));
696                 continue;
697             }
698
699             // skip padding
700             let foreign_index = next_foreign_arg(llforeign_arg_ty.pad.is_some());
701             let mut llforeign_arg = get_param(llwrapfn, foreign_index);
702
703             debug!("llforeign_arg {}{}: {}", "#",
704                    i, ccx.tn().val_to_string(llforeign_arg));
705             debug!("rust_indirect = {}, foreign_indirect = {}",
706                    rust_indirect, foreign_indirect);
707
708             // Ensure that the foreign argument is indirect (by
709             // pointer).  It makes adapting types easier, since we can
710             // always just bitcast pointers.
711             if !foreign_indirect {
712                 llforeign_arg = if ty::type_is_bool(rust_ty) {
713                     let lltemp = builder.alloca(Type::bool(ccx), "");
714                     builder.store(builder.zext(llforeign_arg, Type::bool(ccx)), lltemp);
715                     lltemp
716                 } else {
717                     let lltemp = builder.alloca(val_ty(llforeign_arg), "");
718                     builder.store(llforeign_arg, lltemp);
719                     lltemp
720                 }
721             }
722
723             // If the types in the ABI and the Rust types don't match,
724             // bitcast the llforeign_arg pointer so it matches the types
725             // Rust expects.
726             if llforeign_arg_ty.cast.is_some() {
727                 assert!(!foreign_indirect);
728                 llforeign_arg = builder.bitcast(llforeign_arg, llrust_ty.ptr_to());
729             }
730
731             let llrust_arg = if rust_indirect {
732                 llforeign_arg
733             } else {
734                 if ty::type_is_bool(rust_ty) {
735                     let tmp = builder.load_range_assert(llforeign_arg, 0, 2, llvm::False);
736                     builder.trunc(tmp, Type::i1(ccx))
737                 } else {
738                     builder.load(llforeign_arg)
739                 }
740             };
741
742             debug!("llrust_arg {}{}: {}", "#",
743                    i, ccx.tn().val_to_string(llrust_arg));
744             llrust_args.push(llrust_arg);
745         }
746
747         // Perform the call itself
748         debug!("calling llrustfn = {}, t = {}",
749                ccx.tn().val_to_string(llrustfn), t.repr(ccx.tcx()));
750         let attributes = base::get_fn_llvm_attributes(ccx, t);
751         let llrust_ret_val = builder.call(llrustfn, llrust_args[], Some(attributes));
752
753         // Get the return value where the foreign fn expects it.
754         let llforeign_ret_ty = match tys.fn_ty.ret_ty.cast {
755             Some(ty) => ty,
756             None => tys.fn_ty.ret_ty.ty
757         };
758         match foreign_outptr {
759             None if !tys.llsig.ret_def => {
760                 // Function returns `()` or `bot`, which in Rust is the LLVM
761                 // type "{}" but in foreign ABIs is "Void".
762                 builder.ret_void();
763             }
764
765             None if rust_uses_outptr => {
766                 // Rust uses an outpointer, but the foreign ABI does not. Load.
767                 let llrust_outptr = return_alloca.unwrap();
768                 let llforeign_outptr_casted =
769                     builder.bitcast(llrust_outptr, llforeign_ret_ty.ptr_to());
770                 let llforeign_retval = builder.load(llforeign_outptr_casted);
771                 builder.ret(llforeign_retval);
772             }
773
774             None if llforeign_ret_ty != llrust_ret_ty => {
775                 // Neither ABI uses an outpointer, but the types don't
776                 // quite match. Must cast. Probably we should try and
777                 // examine the types and use a concrete llvm cast, but
778                 // right now we just use a temp memory location and
779                 // bitcast the pointer, which is the same thing the
780                 // old wrappers used to do.
781                 let lltemp = builder.alloca(llforeign_ret_ty, "");
782                 let lltemp_casted = builder.bitcast(lltemp, llrust_ret_ty.ptr_to());
783                 builder.store(llrust_ret_val, lltemp_casted);
784                 let llforeign_retval = builder.load(lltemp);
785                 builder.ret(llforeign_retval);
786             }
787
788             None => {
789                 // Neither ABI uses an outpointer, and the types
790                 // match. Easy peasy.
791                 builder.ret(llrust_ret_val);
792             }
793
794             Some(llforeign_outptr) if !rust_uses_outptr => {
795                 // Foreign ABI requires an out pointer, but Rust doesn't.
796                 // Store Rust return value.
797                 let llforeign_outptr_casted =
798                     builder.bitcast(llforeign_outptr, llrust_retptr_ty);
799                 builder.store(llrust_ret_val, llforeign_outptr_casted);
800                 builder.ret_void();
801             }
802
803             Some(_) => {
804                 // Both ABIs use outpointers. Easy peasy.
805                 builder.ret_void();
806             }
807         }
808     }
809 }
810
811 ///////////////////////////////////////////////////////////////////////////
812 // General ABI Support
813 //
814 // This code is kind of a confused mess and needs to be reworked given
815 // the massive simplifications that have occurred.
816
817 pub fn link_name(i: &ast::ForeignItem) -> InternedString {
818     match attr::first_attr_value_str_by_name(i.attrs[], "link_name") {
819         Some(ln) => ln.clone(),
820         None => match weak_lang_items::link_name(i.attrs[]) {
821             Some(name) => name,
822             None => token::get_ident(i.ident),
823         }
824     }
825 }
826
827 /// The ForeignSignature is the LLVM types of the arguments/return type of a function. Note that
828 /// these LLVM types are not quite the same as the LLVM types would be for a native Rust function
829 /// because foreign functions just plain ignore modes. They also don't pass aggregate values by
830 /// pointer like we do.
831 fn foreign_signature<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
832                                fn_sig: &ty::PolyFnSig<'tcx>, arg_tys: &[Ty<'tcx>])
833                                -> LlvmSignature {
834     let llarg_tys = arg_tys.iter().map(|&arg| arg_type_of(ccx, arg)).collect();
835     let (llret_ty, ret_def) = match fn_sig.0.output {
836         ty::FnConverging(ret_ty) =>
837             (type_of::arg_type_of(ccx, ret_ty), !return_type_is_void(ccx, ret_ty)),
838         ty::FnDiverging =>
839             (Type::nil(ccx), false)
840     };
841     LlvmSignature {
842         llarg_tys: llarg_tys,
843         llret_ty: llret_ty,
844         ret_def: ret_def
845     }
846 }
847
848 fn foreign_types_for_id<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
849                                   id: ast::NodeId) -> ForeignTypes<'tcx> {
850     foreign_types_for_fn_ty(ccx, ty::node_id_to_type(ccx.tcx(), id))
851 }
852
853 fn foreign_types_for_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
854                                      ty: Ty<'tcx>) -> ForeignTypes<'tcx> {
855     let fn_sig = match ty.sty {
856         ty::ty_bare_fn(_, ref fn_ty) => fn_ty.sig.clone(),
857         _ => ccx.sess().bug("foreign_types_for_fn_ty called on non-function type")
858     };
859     let llsig = foreign_signature(ccx, &fn_sig, fn_sig.0.inputs.as_slice());
860     let fn_ty = cabi::compute_abi_info(ccx,
861                                        llsig.llarg_tys[],
862                                        llsig.llret_ty,
863                                        llsig.ret_def);
864     debug!("foreign_types_for_fn_ty(\
865            ty={}, \
866            llsig={} -> {}, \
867            fn_ty={} -> {}, \
868            ret_def={}",
869            ty.repr(ccx.tcx()),
870            ccx.tn().types_to_str(llsig.llarg_tys[]),
871            ccx.tn().type_to_string(llsig.llret_ty),
872            ccx.tn().types_to_str(fn_ty.arg_tys.iter().map(|t| t.ty).collect::<Vec<_>>()[]),
873            ccx.tn().type_to_string(fn_ty.ret_ty.ty),
874            llsig.ret_def);
875
876     ForeignTypes {
877         fn_sig: fn_sig,
878         llsig: llsig,
879         fn_ty: fn_ty
880     }
881 }
882
883 fn lltype_for_fn_from_foreign_types(ccx: &CrateContext, tys: &ForeignTypes) -> Type {
884     let mut llargument_tys = Vec::new();
885
886     let ret_ty = tys.fn_ty.ret_ty;
887     let llreturn_ty = if ret_ty.is_indirect() {
888         llargument_tys.push(ret_ty.ty.ptr_to());
889         Type::void(ccx)
890     } else {
891         match ret_ty.cast {
892             Some(ty) => ty,
893             None => ret_ty.ty
894         }
895     };
896
897     for &arg_ty in tys.fn_ty.arg_tys.iter() {
898         if arg_ty.is_ignore() {
899             continue;
900         }
901         // add padding
902         match arg_ty.pad {
903             Some(ty) => llargument_tys.push(ty),
904             None => ()
905         }
906
907         let llarg_ty = if arg_ty.is_indirect() {
908             arg_ty.ty.ptr_to()
909         } else {
910             match arg_ty.cast {
911                 Some(ty) => ty,
912                 None => arg_ty.ty
913             }
914         };
915
916         llargument_tys.push(llarg_ty);
917     }
918
919     if tys.fn_sig.0.variadic {
920         Type::variadic_func(llargument_tys.as_slice(), &llreturn_ty)
921     } else {
922         Type::func(llargument_tys[], &llreturn_ty)
923     }
924 }
925
926 pub fn lltype_for_foreign_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
927                                        ty: Ty<'tcx>) -> Type {
928     lltype_for_fn_from_foreign_types(ccx, &foreign_types_for_fn_ty(ccx, ty))
929 }
930
931 fn add_argument_attributes(tys: &ForeignTypes,
932                            llfn: ValueRef) {
933     let mut i = if tys.fn_ty.ret_ty.is_indirect() {
934         1i
935     } else {
936         0i
937     };
938
939     match tys.fn_ty.ret_ty.attr {
940         Some(attr) => unsafe {
941             llvm::LLVMAddFunctionAttribute(llfn, i as c_uint, attr.bits() as u64);
942         },
943         None => {}
944     }
945
946     i += 1;
947
948     for &arg_ty in tys.fn_ty.arg_tys.iter() {
949         if arg_ty.is_ignore() {
950             continue;
951         }
952         // skip padding
953         if arg_ty.pad.is_some() { i += 1; }
954
955         match arg_ty.attr {
956             Some(attr) => unsafe {
957                 llvm::LLVMAddFunctionAttribute(llfn, i as c_uint, attr.bits() as u64);
958             },
959             None => ()
960         }
961
962         i += 1;
963     }
964 }