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