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