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