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