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