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