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