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