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