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