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