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