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