]>
Commit | Line | Data |
---|---|---|
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 | ||
12 | use back::{link}; | |
13 | use llvm::{ValueRef, CallConv, get_param}; | |
14 | use llvm; | |
15 | use middle::weak_lang_items; | |
16 | use trans::base::{llvm_linkage_by_name, push_ctxt}; | |
17 | use trans::base; | |
18 | use trans::build::*; | |
19 | use trans::cabi; | |
20 | use trans::common::*; | |
21 | use trans::machine; | |
22 | use trans::monomorphize; | |
23 | use trans::type_::Type; | |
24 | use trans::type_of::*; | |
25 | use trans::type_of; | |
26 | use middle::ty::{self, Ty}; | |
27 | use middle::subst::Substs; | |
28 | ||
29 | use std::ffi::CString; | |
30 | use std::cmp; | |
31 | use libc::c_uint; | |
32 | use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi}; | |
33 | use syntax::abi::{RustIntrinsic, Rust, RustCall, Stdcall, Fastcall, System}; | |
34 | use syntax::codemap::Span; | |
35 | use syntax::parse::token::{InternedString, special_idents}; | |
36 | use syntax::parse::token; | |
37 | use syntax::{ast}; | |
38 | use syntax::{attr, ast_map}; | |
39 | use util::ppaux::Repr; | |
40 | ||
41 | /////////////////////////////////////////////////////////////////////////// | |
42 | // Type definitions | |
43 | ||
44 | struct 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 | ||
56 | struct 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 | ||
74 | pub 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 | ||
106 | pub 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. | |
166 | pub 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. | |
215 | pub 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 | ||
429 | pub 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 | ||
479 | pub 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 | ||
498 | pub 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 | ||
521 | pub 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 | ||
819 | pub 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. | |
833 | fn 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 | ||
851 | fn 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 | ||
856 | fn 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 | ||
887 | fn 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 | ||
930 | pub 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 | ||
935 | fn 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 | } |