]>
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 | ||
c34b1796 | 12 | use back::link; |
1a4d82fc JJ |
13 | use llvm::{ValueRef, CallConv, get_param}; |
14 | use llvm; | |
15 | use middle::weak_lang_items; | |
9346a6ac | 16 | use trans::attributes; |
1a4d82fc JJ |
17 | use trans::base::{llvm_linkage_by_name, push_ctxt}; |
18 | use trans::base; | |
19 | use trans::build::*; | |
20 | use trans::cabi; | |
21 | use trans::common::*; | |
85aaf69f | 22 | use trans::debuginfo::DebugLoc; |
9346a6ac | 23 | use trans::declare; |
1a4d82fc JJ |
24 | use trans::machine; |
25 | use trans::monomorphize; | |
26 | use trans::type_::Type; | |
27 | use trans::type_of::*; | |
28 | use trans::type_of; | |
29 | use middle::ty::{self, Ty}; | |
30 | use middle::subst::Substs; | |
31 | ||
1a4d82fc JJ |
32 | use std::cmp; |
33 | use libc::c_uint; | |
34 | use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi}; | |
35 | use syntax::abi::{RustIntrinsic, Rust, RustCall, Stdcall, Fastcall, System}; | |
36 | use syntax::codemap::Span; | |
37 | use syntax::parse::token::{InternedString, special_idents}; | |
38 | use syntax::parse::token; | |
c34b1796 | 39 | use syntax::ast; |
1a4d82fc | 40 | use syntax::{attr, ast_map}; |
85aaf69f | 41 | use syntax::print::pprust; |
1a4d82fc JJ |
42 | use util::ppaux::Repr; |
43 | ||
44 | /////////////////////////////////////////////////////////////////////////// | |
45 | // Type definitions | |
46 | ||
47 | struct 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 | ||
59 | struct 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 | ||
77 | pub 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 | ||
109 | pub 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 | |
165 | pub 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. | |
182 | pub 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. | |
225 | pub 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 | |
352 | attrs.arg(1, llvm::NoAliasAttribute) | |
353 | .arg(1, llvm::NoCaptureAttribute) | |
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. | |
443 | fn 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 |
465 | pub 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 | ||
521 | pub 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 | ||
541 | pub 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 | ||
564 | pub 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()); | |
805 | builder.load(tmp) | |
1a4d82fc JJ |
806 | } else { |
807 | builder.load(llforeign_arg) | |
808 | } | |
809 | }; | |
810 | ||
811 | debug!("llrust_arg {}{}: {}", "#", | |
812 | i, ccx.tn().val_to_string(llrust_arg)); | |
813 | llrust_args.push(llrust_arg); | |
814 | } | |
815 | ||
816 | // Perform the call itself | |
817 | debug!("calling llrustfn = {}, t = {}", | |
818 | ccx.tn().val_to_string(llrustfn), t.repr(ccx.tcx())); | |
9346a6ac | 819 | let attributes = attributes::from_fn_type(ccx, t); |
85aaf69f | 820 | let llrust_ret_val = builder.call(llrustfn, &llrust_args, Some(attributes)); |
1a4d82fc JJ |
821 | |
822 | // Get the return value where the foreign fn expects it. | |
823 | let llforeign_ret_ty = match tys.fn_ty.ret_ty.cast { | |
824 | Some(ty) => ty, | |
825 | None => tys.fn_ty.ret_ty.ty | |
826 | }; | |
827 | match foreign_outptr { | |
828 | None if !tys.llsig.ret_def => { | |
829 | // Function returns `()` or `bot`, which in Rust is the LLVM | |
830 | // type "{}" but in foreign ABIs is "Void". | |
831 | builder.ret_void(); | |
832 | } | |
833 | ||
834 | None if rust_uses_outptr => { | |
835 | // Rust uses an outpointer, but the foreign ABI does not. Load. | |
836 | let llrust_outptr = return_alloca.unwrap(); | |
837 | let llforeign_outptr_casted = | |
838 | builder.bitcast(llrust_outptr, llforeign_ret_ty.ptr_to()); | |
839 | let llforeign_retval = builder.load(llforeign_outptr_casted); | |
840 | builder.ret(llforeign_retval); | |
841 | } | |
842 | ||
843 | None if llforeign_ret_ty != llrust_ret_ty => { | |
844 | // Neither ABI uses an outpointer, but the types don't | |
845 | // quite match. Must cast. Probably we should try and | |
846 | // examine the types and use a concrete llvm cast, but | |
847 | // right now we just use a temp memory location and | |
848 | // bitcast the pointer, which is the same thing the | |
849 | // old wrappers used to do. | |
850 | let lltemp = builder.alloca(llforeign_ret_ty, ""); | |
851 | let lltemp_casted = builder.bitcast(lltemp, llrust_ret_ty.ptr_to()); | |
852 | builder.store(llrust_ret_val, lltemp_casted); | |
853 | let llforeign_retval = builder.load(lltemp); | |
854 | builder.ret(llforeign_retval); | |
855 | } | |
856 | ||
857 | None => { | |
858 | // Neither ABI uses an outpointer, and the types | |
859 | // match. Easy peasy. | |
860 | builder.ret(llrust_ret_val); | |
861 | } | |
862 | ||
863 | Some(llforeign_outptr) if !rust_uses_outptr => { | |
864 | // Foreign ABI requires an out pointer, but Rust doesn't. | |
865 | // Store Rust return value. | |
866 | let llforeign_outptr_casted = | |
85aaf69f | 867 | builder.bitcast(llforeign_outptr, llrust_ret_ty.ptr_to()); |
1a4d82fc JJ |
868 | builder.store(llrust_ret_val, llforeign_outptr_casted); |
869 | builder.ret_void(); | |
870 | } | |
871 | ||
872 | Some(_) => { | |
873 | // Both ABIs use outpointers. Easy peasy. | |
874 | builder.ret_void(); | |
875 | } | |
876 | } | |
877 | } | |
878 | } | |
879 | ||
880 | /////////////////////////////////////////////////////////////////////////// | |
881 | // General ABI Support | |
882 | // | |
883 | // This code is kind of a confused mess and needs to be reworked given | |
884 | // the massive simplifications that have occurred. | |
885 | ||
886 | pub fn link_name(i: &ast::ForeignItem) -> InternedString { | |
c34b1796 | 887 | match attr::first_attr_value_str_by_name(&i.attrs, "link_name") { |
1a4d82fc | 888 | Some(ln) => ln.clone(), |
c34b1796 | 889 | None => match weak_lang_items::link_name(&i.attrs) { |
1a4d82fc JJ |
890 | Some(name) => name, |
891 | None => token::get_ident(i.ident), | |
892 | } | |
893 | } | |
894 | } | |
895 | ||
896 | /// The ForeignSignature is the LLVM types of the arguments/return type of a function. Note that | |
897 | /// these LLVM types are not quite the same as the LLVM types would be for a native Rust function | |
898 | /// because foreign functions just plain ignore modes. They also don't pass aggregate values by | |
899 | /// pointer like we do. | |
900 | fn foreign_signature<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, | |
901 | fn_sig: &ty::FnSig<'tcx>, | |
902 | arg_tys: &[Ty<'tcx>]) | |
903 | -> LlvmSignature { | |
85aaf69f | 904 | let llarg_tys = arg_tys.iter().map(|&arg| foreign_arg_type_of(ccx, arg)).collect(); |
1a4d82fc JJ |
905 | let (llret_ty, ret_def) = match fn_sig.output { |
906 | ty::FnConverging(ret_ty) => | |
85aaf69f | 907 | (type_of::foreign_arg_type_of(ccx, ret_ty), !return_type_is_void(ccx, ret_ty)), |
1a4d82fc JJ |
908 | ty::FnDiverging => |
909 | (Type::nil(ccx), false) | |
910 | }; | |
911 | LlvmSignature { | |
912 | llarg_tys: llarg_tys, | |
913 | llret_ty: llret_ty, | |
914 | ret_def: ret_def | |
915 | } | |
916 | } | |
917 | ||
918 | fn foreign_types_for_id<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, | |
919 | id: ast::NodeId) -> ForeignTypes<'tcx> { | |
920 | foreign_types_for_fn_ty(ccx, ty::node_id_to_type(ccx.tcx(), id)) | |
921 | } | |
922 | ||
923 | fn foreign_types_for_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, | |
924 | ty: Ty<'tcx>) -> ForeignTypes<'tcx> { | |
925 | let fn_sig = match ty.sty { | |
926 | ty::ty_bare_fn(_, ref fn_ty) => &fn_ty.sig, | |
927 | _ => ccx.sess().bug("foreign_types_for_fn_ty called on non-function type") | |
928 | }; | |
929 | let fn_sig = ty::erase_late_bound_regions(ccx.tcx(), fn_sig); | |
85aaf69f | 930 | let llsig = foreign_signature(ccx, &fn_sig, &fn_sig.inputs); |
1a4d82fc | 931 | let fn_ty = cabi::compute_abi_info(ccx, |
c34b1796 | 932 | &llsig.llarg_tys, |
1a4d82fc JJ |
933 | llsig.llret_ty, |
934 | llsig.ret_def); | |
935 | debug!("foreign_types_for_fn_ty(\ | |
936 | ty={}, \ | |
937 | llsig={} -> {}, \ | |
938 | fn_ty={} -> {}, \ | |
939 | ret_def={}", | |
940 | ty.repr(ccx.tcx()), | |
c34b1796 | 941 | ccx.tn().types_to_str(&llsig.llarg_tys), |
1a4d82fc | 942 | ccx.tn().type_to_string(llsig.llret_ty), |
85aaf69f | 943 | ccx.tn().types_to_str(&fn_ty.arg_tys.iter().map(|t| t.ty).collect::<Vec<_>>()), |
1a4d82fc JJ |
944 | ccx.tn().type_to_string(fn_ty.ret_ty.ty), |
945 | llsig.ret_def); | |
946 | ||
947 | ForeignTypes { | |
948 | fn_sig: fn_sig, | |
949 | llsig: llsig, | |
950 | fn_ty: fn_ty | |
951 | } | |
952 | } | |
953 | ||
954 | fn lltype_for_fn_from_foreign_types(ccx: &CrateContext, tys: &ForeignTypes) -> Type { | |
955 | let mut llargument_tys = Vec::new(); | |
956 | ||
957 | let ret_ty = tys.fn_ty.ret_ty; | |
958 | let llreturn_ty = if ret_ty.is_indirect() { | |
959 | llargument_tys.push(ret_ty.ty.ptr_to()); | |
960 | Type::void(ccx) | |
961 | } else { | |
962 | match ret_ty.cast { | |
963 | Some(ty) => ty, | |
964 | None => ret_ty.ty | |
965 | } | |
966 | }; | |
967 | ||
85aaf69f | 968 | for &arg_ty in &tys.fn_ty.arg_tys { |
1a4d82fc JJ |
969 | if arg_ty.is_ignore() { |
970 | continue; | |
971 | } | |
972 | // add padding | |
973 | match arg_ty.pad { | |
974 | Some(ty) => llargument_tys.push(ty), | |
975 | None => () | |
976 | } | |
977 | ||
978 | let llarg_ty = if arg_ty.is_indirect() { | |
979 | arg_ty.ty.ptr_to() | |
980 | } else { | |
981 | match arg_ty.cast { | |
982 | Some(ty) => ty, | |
983 | None => arg_ty.ty | |
984 | } | |
985 | }; | |
986 | ||
987 | llargument_tys.push(llarg_ty); | |
988 | } | |
989 | ||
990 | if tys.fn_sig.variadic { | |
85aaf69f | 991 | Type::variadic_func(&llargument_tys, &llreturn_ty) |
1a4d82fc | 992 | } else { |
85aaf69f | 993 | Type::func(&llargument_tys[..], &llreturn_ty) |
1a4d82fc JJ |
994 | } |
995 | } | |
996 | ||
997 | pub fn lltype_for_foreign_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, | |
998 | ty: Ty<'tcx>) -> Type { | |
999 | lltype_for_fn_from_foreign_types(ccx, &foreign_types_for_fn_ty(ccx, ty)) | |
1000 | } | |
1001 | ||
1002 | fn add_argument_attributes(tys: &ForeignTypes, | |
1003 | llfn: ValueRef) { | |
1004 | let mut i = if tys.fn_ty.ret_ty.is_indirect() { | |
85aaf69f | 1005 | 1 |
1a4d82fc | 1006 | } else { |
85aaf69f | 1007 | 0 |
1a4d82fc JJ |
1008 | }; |
1009 | ||
1010 | match tys.fn_ty.ret_ty.attr { | |
1011 | Some(attr) => unsafe { | |
1012 | llvm::LLVMAddFunctionAttribute(llfn, i as c_uint, attr.bits() as u64); | |
1013 | }, | |
1014 | None => {} | |
1015 | } | |
1016 | ||
1017 | i += 1; | |
1018 | ||
85aaf69f | 1019 | for &arg_ty in &tys.fn_ty.arg_tys { |
1a4d82fc JJ |
1020 | if arg_ty.is_ignore() { |
1021 | continue; | |
1022 | } | |
1023 | // skip padding | |
1024 | if arg_ty.pad.is_some() { i += 1; } | |
1025 | ||
1026 | match arg_ty.attr { | |
1027 | Some(attr) => unsafe { | |
1028 | llvm::LLVMAddFunctionAttribute(llfn, i as c_uint, attr.bits() as u64); | |
1029 | }, | |
1030 | None => () | |
1031 | } | |
1032 | ||
1033 | i += 1; | |
1034 | } | |
1035 | } |