1 // Copyright 2012-2016 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.
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.
11 use llvm
::{self, ValueRef}
;
14 use common
::{type_is_fat_ptr, BlockAndBuilder}
;
15 use context
::CrateContext
;
25 use machine
::{llalign_of_min, llsize_of, llsize_of_real}
;
30 use rustc
::ty
::{self, Ty}
;
34 pub use syntax
::abi
::Abi
;
35 pub use rustc
::ty
::layout
::{FAT_PTR_ADDR, FAT_PTR_EXTRA}
;
37 #[derive(Clone, Copy, PartialEq, Debug)]
39 /// Pass the argument directly using the normal converted
40 /// LLVM type or by coercing to another specified type
42 /// Pass the argument indirectly via a hidden pointer
44 /// Ignore the argument (useful for empty struct)
48 /// Information about how a specific C type
49 /// should be passed to or returned from a function
51 /// This is borrowed from clang's ABIInfo.h
52 #[derive(Clone, Copy, Debug)]
55 /// Original LLVM type
56 pub original_ty
: Type
,
57 /// Sizing LLVM type (pointers are opaque).
58 /// Unlike original_ty, this is guaranteed to be complete.
60 /// For example, while we're computing the function pointer type in
61 /// `struct Foo(fn(Foo));`, `original_ty` is still LLVM's `%Foo = {}`.
62 /// The field type will likely end up being `void(%Foo)*`, but we cannot
63 /// use `%Foo` to compute properties (e.g. size and alignment) of `Foo`,
64 /// until `%Foo` is completed by having all of its field types inserted,
65 /// so `ty` holds the "sizing type" of `Foo`, which replaces all pointers
66 /// with opaque ones, resulting in `{i8*}` for `Foo`.
67 /// ABI-specific logic can then look at the size, alignment and fields of
68 /// `{i8*}` in order to determine how the argument will be passed.
69 /// Only later will `original_ty` aka `%Foo` be used in the LLVM function
70 /// pointer type, without ever having introspected it.
72 /// Signedness for integer types, None for other types
73 pub signedness
: Option
<bool
>,
75 pub cast
: Option
<Type
>,
76 /// Dummy argument, which is emitted before the real argument
77 pub pad
: Option
<Type
>,
78 /// LLVM attributes of argument
79 pub attrs
: llvm
::Attributes
83 fn new(original_ty
: Type
, ty
: Type
) -> ArgType
{
85 kind
: ArgKind
::Direct
,
86 original_ty
: original_ty
,
91 attrs
: llvm
::Attributes
::default()
95 pub fn make_indirect(&mut self, ccx
: &CrateContext
) {
96 assert_eq
!(self.kind
, ArgKind
::Direct
);
98 // Wipe old attributes, likely not valid through indirection.
99 self.attrs
= llvm
::Attributes
::default();
101 let llarg_sz
= llsize_of_real(ccx
, self.ty
);
103 // For non-immediate arguments the callee gets its own copy of
104 // the value on the stack, so there are no aliases. It's also
105 // program-invisible so can't possibly capture
106 self.attrs
.set(llvm
::Attribute
::NoAlias
)
107 .set(llvm
::Attribute
::NoCapture
)
108 .set_dereferenceable(llarg_sz
);
110 self.kind
= ArgKind
::Indirect
;
113 pub fn ignore(&mut self) {
114 assert_eq
!(self.kind
, ArgKind
::Direct
);
115 self.kind
= ArgKind
::Ignore
;
118 pub fn extend_integer_width_to(&mut self, bits
: u64) {
119 // Only integers have signedness
120 if let Some(signed
) = self.signedness
{
121 if self.ty
.int_width() < bits
{
122 self.attrs
.set(if signed
{
123 llvm
::Attribute
::SExt
125 llvm
::Attribute
::ZExt
131 pub fn is_indirect(&self) -> bool
{
132 self.kind
== ArgKind
::Indirect
135 pub fn is_ignore(&self) -> bool
{
136 self.kind
== ArgKind
::Ignore
139 /// Get the LLVM type for an lvalue of the original Rust type of
140 /// this argument/return, i.e. the result of `type_of::type_of`.
141 pub fn memory_ty(&self, ccx
: &CrateContext
) -> Type
{
142 if self.original_ty
== Type
::i1(ccx
) {
149 /// Store a direct/indirect value described by this ArgType into a
150 /// lvalue for the original Rust type of this argument/return.
151 /// Can be used for both storing formal arguments into Rust variables
152 /// or results of call/invoke instructions into their destinations.
153 pub fn store(&self, b
: &Builder
, mut val
: ValueRef
, dst
: ValueRef
) {
154 if self.is_ignore() {
157 if self.is_indirect() {
158 let llsz
= llsize_of(b
.ccx
, self.ty
);
159 let llalign
= llalign_of_min(b
.ccx
, self.ty
);
160 base
::call_memcpy(b
, dst
, val
, llsz
, llalign
as u32);
161 } else if let Some(ty
) = self.cast
{
162 let cast_dst
= b
.pointercast(dst
, ty
.ptr_to());
163 let store
= b
.store(val
, cast_dst
);
164 let llalign
= llalign_of_min(b
.ccx
, self.ty
);
166 llvm
::LLVMSetAlignment(store
, llalign
);
169 if self.original_ty
== Type
::i1(b
.ccx
) {
170 val
= b
.zext(val
, Type
::i8(b
.ccx
));
176 pub fn store_fn_arg(&self, bcx
: &BlockAndBuilder
, idx
: &mut usize, dst
: ValueRef
) {
177 if self.pad
.is_some() {
180 if self.is_ignore() {
183 let val
= llvm
::get_param(bcx
.fcx().llfn
, *idx
as c_uint
);
185 self.store(bcx
, val
, dst
);
189 /// Metadata describing how the arguments to a native function
190 /// should be passed in order to respect the native ABI.
192 /// I will do my best to describe this structure, but these
193 /// comments are reverse-engineered and may be inaccurate. -NDM
195 /// The LLVM types of each argument.
196 pub args
: Vec
<ArgType
>,
198 /// LLVM return type.
203 pub cconv
: llvm
::CallConv
207 pub fn new
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
209 sig
: &ty
::FnSig
<'tcx
>,
210 extra_args
: &[Ty
<'tcx
>]) -> FnType
{
211 let mut fn_ty
= FnType
::unadjusted(ccx
, abi
, sig
, extra_args
);
212 fn_ty
.adjust_for_abi(ccx
, abi
, sig
);
216 pub fn unadjusted
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
218 sig
: &ty
::FnSig
<'tcx
>,
219 extra_args
: &[Ty
<'tcx
>]) -> FnType
{
221 let cconv
= match ccx
.sess().target
.target
.adjust_abi(abi
) {
222 RustIntrinsic
| PlatformIntrinsic
|
223 Rust
| RustCall
=> llvm
::CCallConv
,
225 // It's the ABI's job to select this, not us.
226 System
=> bug
!("system abi should be selected elsewhere"),
228 Stdcall
=> llvm
::X86StdcallCallConv
,
229 Fastcall
=> llvm
::X86FastcallCallConv
,
230 Vectorcall
=> llvm
::X86_VectorCall
,
231 C
=> llvm
::CCallConv
,
232 Win64
=> llvm
::X86_64_Win64
,
234 // These API constants ought to be more specific...
235 Cdecl
=> llvm
::CCallConv
,
236 Aapcs
=> llvm
::CCallConv
,
239 let mut inputs
= &sig
.inputs
[..];
240 let extra_args
= if abi
== RustCall
{
241 assert
!(!sig
.variadic
&& extra_args
.is_empty());
243 match inputs
[inputs
.len() - 1].sty
{
244 ty
::TyTuple(ref tupled_arguments
) => {
245 inputs
= &inputs
[..inputs
.len() - 1];
246 &tupled_arguments
[..]
249 bug
!("argument to function with \"rust-call\" ABI \
254 assert
!(sig
.variadic
|| extra_args
.is_empty());
258 let target
= &ccx
.sess().target
.target
;
259 let win_x64_gnu
= target
.target_os
== "windows"
260 && target
.arch
== "x86_64"
261 && target
.target_env
== "gnu";
262 let rust_abi
= match abi
{
263 RustIntrinsic
| PlatformIntrinsic
| Rust
| RustCall
=> true,
267 let arg_of
= |ty
: Ty
<'tcx
>, is_return
: bool
| {
269 let llty
= Type
::i1(ccx
);
270 let mut arg
= ArgType
::new(llty
, llty
);
271 arg
.attrs
.set(llvm
::Attribute
::ZExt
);
274 let mut arg
= ArgType
::new(type_of
::type_of(ccx
, ty
),
275 type_of
::sizing_type_of(ccx
, ty
));
276 if ty
.is_integral() {
277 arg
.signedness
= Some(ty
.is_signed());
279 if llsize_of_real(ccx
, arg
.ty
) == 0 {
280 // For some forsaken reason, x86_64-pc-windows-gnu
281 // doesn't ignore zero-sized struct arguments.
282 if is_return
|| rust_abi
|| !win_x64_gnu
{
290 let ret_ty
= match sig
.output
{
291 ty
::FnConverging(ret_ty
) => ret_ty
,
292 ty
::FnDiverging
=> ccx
.tcx().mk_nil()
294 let mut ret
= arg_of(ret_ty
, true);
296 if !type_is_fat_ptr(ccx
.tcx(), ret_ty
) {
297 // The `noalias` attribute on the return value is useful to a
298 // function ptr caller.
299 if let ty
::TyBox(_
) = ret_ty
.sty
{
300 // `Box` pointer return values never alias because ownership
302 ret
.attrs
.set(llvm
::Attribute
::NoAlias
);
305 // We can also mark the return value as `dereferenceable` in certain cases
307 // These are not really pointers but pairs, (pointer, len)
308 ty
::TyRef(_
, ty
::TypeAndMut { ty, .. }
) |
310 let llty
= type_of
::sizing_type_of(ccx
, ty
);
311 let llsz
= llsize_of_real(ccx
, llty
);
312 ret
.attrs
.set_dereferenceable(llsz
);
318 let mut args
= Vec
::with_capacity(inputs
.len() + extra_args
.len());
320 // Handle safe Rust thin and fat pointers.
321 let rust_ptr_attrs
= |ty
: Ty
<'tcx
>, arg
: &mut ArgType
| match ty
.sty
{
322 // `Box` pointer parameters never alias because ownership is transferred
323 ty
::TyBox(inner
) => {
324 arg
.attrs
.set(llvm
::Attribute
::NoAlias
);
328 ty
::TyRef(b
, mt
) => {
329 use rustc
::ty
::{BrAnon, ReLateBound}
;
331 // `&mut` pointer parameters never alias other parameters, or mutable global data
333 // `&T` where `T` contains no `UnsafeCell<U>` is immutable, and can be marked as
334 // both `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely
335 // on memory dependencies rather than pointer equality
336 let interior_unsafe
= mt
.ty
.type_contents(ccx
.tcx()).interior_unsafe();
338 if mt
.mutbl
!= hir
::MutMutable
&& !interior_unsafe
{
339 arg
.attrs
.set(llvm
::Attribute
::NoAlias
);
342 if mt
.mutbl
== hir
::MutImmutable
&& !interior_unsafe
{
343 arg
.attrs
.set(llvm
::Attribute
::ReadOnly
);
346 // When a reference in an argument has no named lifetime, it's
347 // impossible for that reference to escape this function
348 // (returned or stored beyond the call by a closure).
349 if let ReLateBound(_
, BrAnon(_
)) = *b
{
350 arg
.attrs
.set(llvm
::Attribute
::NoCapture
);
358 for ty
in inputs
.iter().chain(extra_args
.iter()) {
359 let mut arg
= arg_of(ty
, false);
361 if type_is_fat_ptr(ccx
.tcx(), ty
) {
362 let original_tys
= arg
.original_ty
.field_types();
363 let sizing_tys
= arg
.ty
.field_types();
364 assert_eq
!((original_tys
.len(), sizing_tys
.len()), (2, 2));
366 let mut data
= ArgType
::new(original_tys
[0], sizing_tys
[0]);
367 let mut info
= ArgType
::new(original_tys
[1], sizing_tys
[1]);
369 if let Some(inner
) = rust_ptr_attrs(ty
, &mut data
) {
370 data
.attrs
.set(llvm
::Attribute
::NonNull
);
371 if ccx
.tcx().struct_tail(inner
).is_trait() {
372 info
.attrs
.set(llvm
::Attribute
::NonNull
);
378 if let Some(inner
) = rust_ptr_attrs(ty
, &mut arg
) {
379 let llty
= type_of
::sizing_type_of(ccx
, inner
);
380 let llsz
= llsize_of_real(ccx
, llty
);
381 arg
.attrs
.set_dereferenceable(llsz
);
390 variadic
: sig
.variadic
,
395 pub fn adjust_for_abi
<'a
, 'tcx
>(&mut self,
396 ccx
: &CrateContext
<'a
, 'tcx
>,
398 sig
: &ty
::FnSig
<'tcx
>) {
399 if abi
== Abi
::Rust
|| abi
== Abi
::RustCall
||
400 abi
== Abi
::RustIntrinsic
|| abi
== Abi
::PlatformIntrinsic
{
401 let fixup
= |arg
: &mut ArgType
| {
402 let mut llty
= arg
.ty
;
404 // Replace newtypes with their inner-most type.
405 while llty
.kind() == llvm
::TypeKind
::Struct
{
406 let inner
= llty
.field_types();
407 if inner
.len() != 1 {
413 if !llty
.is_aggregate() {
414 // Scalars and vectors, always immediate.
416 // Needs a cast as we've unpacked a newtype.
417 arg
.cast
= Some(llty
);
422 let size
= llsize_of_real(ccx
, llty
);
423 if size
> llsize_of_real(ccx
, ccx
.int_type()) {
424 arg
.make_indirect(ccx
);
426 // We want to pass small aggregates as immediates, but using
427 // a LLVM aggregate type for this leads to bad optimizations,
428 // so we pick an appropriately sized integer type instead.
429 arg
.cast
= Some(Type
::ix(ccx
, size
* 8));
432 // Fat pointers are returned by-value.
433 if !self.ret
.is_ignore() {
434 if !type_is_fat_ptr(ccx
.tcx(), sig
.output
.unwrap()) {
435 fixup(&mut self.ret
);
438 for arg
in &mut self.args
{
439 if arg
.is_ignore() { continue; }
442 if self.ret
.is_indirect() {
443 self.ret
.attrs
.set(llvm
::Attribute
::StructRet
);
448 match &ccx
.sess().target
.target
.arch
[..] {
449 "x86" => cabi_x86
::compute_abi_info(ccx
, self),
450 "x86_64" => if ccx
.sess().target
.target
.options
.is_like_windows
{
451 cabi_x86_win64
::compute_abi_info(ccx
, self);
453 cabi_x86_64
::compute_abi_info(ccx
, self);
455 "aarch64" => cabi_aarch64
::compute_abi_info(ccx
, self),
457 let flavor
= if ccx
.sess().target
.target
.target_os
== "ios" {
458 cabi_arm
::Flavor
::Ios
460 cabi_arm
::Flavor
::General
462 cabi_arm
::compute_abi_info(ccx
, self, flavor
);
464 "mips" => cabi_mips
::compute_abi_info(ccx
, self),
465 "powerpc" => cabi_powerpc
::compute_abi_info(ccx
, self),
466 "powerpc64" => cabi_powerpc64
::compute_abi_info(ccx
, self),
467 "asmjs" => cabi_asmjs
::compute_abi_info(ccx
, self),
468 a
=> ccx
.sess().fatal(&format
!("unrecognized arch \"{}\" in target specification", a
))
471 if self.ret
.is_indirect() {
472 self.ret
.attrs
.set(llvm
::Attribute
::StructRet
);
476 pub fn llvm_type(&self, ccx
: &CrateContext
) -> Type
{
477 let mut llargument_tys
= Vec
::new();
479 let llreturn_ty
= if self.ret
.is_ignore() {
481 } else if self.ret
.is_indirect() {
482 llargument_tys
.push(self.ret
.original_ty
.ptr_to());
485 self.ret
.cast
.unwrap_or(self.ret
.original_ty
)
488 for arg
in &self.args
{
493 if let Some(ty
) = arg
.pad
{
494 llargument_tys
.push(ty
);
497 let llarg_ty
= if arg
.is_indirect() {
498 arg
.original_ty
.ptr_to()
500 arg
.cast
.unwrap_or(arg
.original_ty
)
503 llargument_tys
.push(llarg_ty
);
507 Type
::variadic_func(&llargument_tys
, &llreturn_ty
)
509 Type
::func(&llargument_tys
, &llreturn_ty
)
513 pub fn apply_attrs_llfn(&self, llfn
: ValueRef
) {
514 let mut i
= if self.ret
.is_indirect() { 1 }
else { 0 }
;
515 if !self.ret
.is_ignore() {
516 self.ret
.attrs
.apply_llfn(i
, llfn
);
519 for arg
in &self.args
{
520 if !arg
.is_ignore() {
521 if arg
.pad
.is_some() { i += 1; }
522 arg
.attrs
.apply_llfn(i
, llfn
);
528 pub fn apply_attrs_callsite(&self, callsite
: ValueRef
) {
529 let mut i
= if self.ret
.is_indirect() { 1 }
else { 0 }
;
530 if !self.ret
.is_ignore() {
531 self.ret
.attrs
.apply_callsite(i
, callsite
);
534 for arg
in &self.args
{
535 if !arg
.is_ignore() {
536 if arg
.pad
.is_some() { i += 1; }
537 arg
.attrs
.apply_callsite(i
, callsite
);
542 if self.cconv
!= llvm
::CCallConv
{
543 llvm
::SetInstructionCallConv(callsite
, self.cconv
);