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, AttributePlace};
14 use common::{ty_fn_sig, C_usize};
15 use context::CodegenCx;
33 use mir::place::PlaceRef;
34 use mir::operand::OperandValue;
36 use type_of::{LayoutLlvmExt, PointerKind};
38 use rustc::ty::{self, Ty};
39 use rustc::ty::layout::{self, Align, Size, TyLayout};
40 use rustc::ty::layout::{HasDataLayout, LayoutOf};
45 pub use syntax::abi::Abi;
46 pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
48 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
50 /// Ignore the argument (useful for empty struct).
52 /// Pass the argument directly.
53 Direct(ArgAttributes),
54 /// Pass a pair's elements directly in two arguments.
55 Pair(ArgAttributes, ArgAttributes),
56 /// Pass the argument after casting it, to either
57 /// a single uniform or a pair of registers.
59 /// Pass the argument indirectly via a hidden pointer.
60 Indirect(ArgAttributes),
63 // Hack to disable non_upper_case_globals only for the bitflags! and not for the rest
65 pub use self::attr_impl::ArgAttribute;
67 #[allow(non_upper_case_globals)]
70 // The subset of llvm::Attribute needed for arguments, packed into a bitfield.
73 pub struct ArgAttribute: u16 {
75 const NoAlias = 1 << 1;
76 const NoCapture = 1 << 2;
77 const NonNull = 1 << 3;
78 const ReadOnly = 1 << 4;
80 const StructRet = 1 << 6;
87 macro_rules! for_each_kind {
88 ($flags: ident, $f: ident, $($kind: ident),+) => ({
89 $(if $flags.contains(ArgAttribute::$kind) { $f(llvm::Attribute::$kind) })+
94 fn for_each_kind<F>(&self, mut f: F) where F: FnMut(llvm::Attribute) {
95 for_each_kind!(self, f,
96 ByVal, NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt, InReg)
100 /// A compact representation of LLVM attributes (at least those relevant for this module)
101 /// that can be manipulated without interacting with LLVM's Attribute machinery.
102 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
103 pub struct ArgAttributes {
104 regular: ArgAttribute,
106 pointee_align: Option<Align>
112 regular: ArgAttribute::default(),
113 pointee_size: Size::from_bytes(0),
118 pub fn set(&mut self, attr: ArgAttribute) -> &mut Self {
119 self.regular = self.regular | attr;
123 pub fn contains(&self, attr: ArgAttribute) -> bool {
124 self.regular.contains(attr)
127 pub fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) {
128 let mut regular = self.regular;
130 let deref = self.pointee_size.bytes();
132 if regular.contains(ArgAttribute::NonNull) {
133 llvm::LLVMRustAddDereferenceableAttr(llfn,
137 llvm::LLVMRustAddDereferenceableOrNullAttr(llfn,
141 regular -= ArgAttribute::NonNull;
143 if let Some(align) = self.pointee_align {
144 llvm::LLVMRustAddAlignmentAttr(llfn,
148 regular.for_each_kind(|attr| attr.apply_llfn(idx, llfn));
152 pub fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef) {
153 let mut regular = self.regular;
155 let deref = self.pointee_size.bytes();
157 if regular.contains(ArgAttribute::NonNull) {
158 llvm::LLVMRustAddDereferenceableCallSiteAttr(callsite,
162 llvm::LLVMRustAddDereferenceableOrNullCallSiteAttr(callsite,
166 regular -= ArgAttribute::NonNull;
168 if let Some(align) = self.pointee_align {
169 llvm::LLVMRustAddAlignmentCallSiteAttr(callsite,
173 regular.for_each_kind(|attr| attr.apply_callsite(idx, callsite));
177 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
184 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
190 macro_rules! reg_ctor {
191 ($name:ident, $kind:ident, $bits:expr) => {
192 pub fn $name() -> Reg {
194 kind: RegKind::$kind,
195 size: Size::from_bits($bits)
202 reg_ctor!(i8, Integer, 8);
203 reg_ctor!(i16, Integer, 16);
204 reg_ctor!(i32, Integer, 32);
205 reg_ctor!(i64, Integer, 64);
207 reg_ctor!(f32, Float, 32);
208 reg_ctor!(f64, Float, 64);
212 pub fn align(&self, cx: &CodegenCx) -> Align {
213 let dl = cx.data_layout();
215 RegKind::Integer => {
216 match self.size.bits() {
218 2...8 => dl.i8_align,
219 9...16 => dl.i16_align,
220 17...32 => dl.i32_align,
221 33...64 => dl.i64_align,
222 65...128 => dl.i128_align,
223 _ => bug!("unsupported integer: {:?}", self)
227 match self.size.bits() {
230 _ => bug!("unsupported float: {:?}", self)
233 RegKind::Vector => dl.vector_align(self.size)
237 pub fn llvm_type(&self, cx: &CodegenCx) -> Type {
239 RegKind::Integer => Type::ix(cx, self.size.bits()),
241 match self.size.bits() {
244 _ => bug!("unsupported float: {:?}", self)
248 Type::vector(&Type::i8(cx), self.size.bytes())
254 /// An argument passed entirely registers with the
255 /// same kind (e.g. HFA / HVA on PPC64 and AArch64).
256 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
260 /// The total size of the argument, which can be:
261 /// * equal to `unit.size` (one scalar/vector)
262 /// * a multiple of `unit.size` (an array of scalar/vectors)
263 /// * if `unit.kind` is `Integer`, the last element
264 /// can be shorter, i.e. `{ i64, i64, i32 }` for
265 /// 64-bit integers with a total size of 20 bytes
269 impl From<Reg> for Uniform {
270 fn from(unit: Reg) -> Uniform {
279 pub fn align(&self, cx: &CodegenCx) -> Align {
283 pub fn llvm_type(&self, cx: &CodegenCx) -> Type {
284 let llunit = self.unit.llvm_type(cx);
286 if self.total <= self.unit.size {
290 let count = self.total.bytes() / self.unit.size.bytes();
291 let rem_bytes = self.total.bytes() % self.unit.size.bytes();
294 return Type::array(&llunit, count);
297 // Only integers can be really split further.
298 assert_eq!(self.unit.kind, RegKind::Integer);
300 let args: Vec<_> = (0..count).map(|_| llunit)
301 .chain(iter::once(Type::ix(cx, rem_bytes * 8)))
304 Type::struct_(cx, &args, false)
308 pub trait LayoutExt<'tcx> {
309 fn is_aggregate(&self) -> bool;
310 fn homogeneous_aggregate<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Option<Reg>;
313 impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> {
314 fn is_aggregate(&self) -> bool {
316 layout::Abi::Uninhabited |
317 layout::Abi::Scalar(_) |
318 layout::Abi::Vector { .. } => false,
319 layout::Abi::ScalarPair(..) |
320 layout::Abi::Aggregate { .. } => true
324 fn homogeneous_aggregate<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Option<Reg> {
326 layout::Abi::Uninhabited => None,
328 // The primitive for this algorithm.
329 layout::Abi::Scalar(ref scalar) => {
330 let kind = match scalar.value {
332 layout::Pointer => RegKind::Integer,
334 layout::F64 => RegKind::Float
342 layout::Abi::Vector { .. } => {
344 kind: RegKind::Vector,
349 layout::Abi::ScalarPair(..) |
350 layout::Abi::Aggregate { .. } => {
351 let mut total = Size::from_bytes(0);
352 let mut result = None;
354 let is_union = match self.fields {
355 layout::FieldPlacement::Array { count, .. } => {
357 return self.field(cx, 0).homogeneous_aggregate(cx);
362 layout::FieldPlacement::Union(_) => true,
363 layout::FieldPlacement::Arbitrary { .. } => false
366 for i in 0..self.fields.count() {
367 if !is_union && total != self.fields.offset(i) {
371 let field = self.field(cx, i);
372 match (result, field.homogeneous_aggregate(cx)) {
373 // The field itself must be a homogeneous aggregate.
374 (_, None) => return None,
375 // If this is the first field, record the unit.
376 (None, Some(unit)) => {
379 // For all following fields, the unit must be the same.
380 (Some(prev_unit), Some(unit)) => {
381 if prev_unit != unit {
387 // Keep track of the offset (without padding).
388 let size = field.size;
390 total = cmp::max(total, size);
396 // There needs to be no padding.
397 if total != self.size {
407 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
408 pub enum CastTarget {
413 impl From<Reg> for CastTarget {
414 fn from(unit: Reg) -> CastTarget {
415 CastTarget::Uniform(Uniform::from(unit))
419 impl From<Uniform> for CastTarget {
420 fn from(uniform: Uniform) -> CastTarget {
421 CastTarget::Uniform(uniform)
426 pub fn size(&self, cx: &CodegenCx) -> Size {
428 CastTarget::Uniform(u) => u.total,
429 CastTarget::Pair(a, b) => {
430 (a.size.abi_align(a.align(cx)) + b.size)
431 .abi_align(self.align(cx))
436 pub fn align(&self, cx: &CodegenCx) -> Align {
438 CastTarget::Uniform(u) => u.align(cx),
439 CastTarget::Pair(a, b) => {
440 cx.data_layout().aggregate_align
447 pub fn llvm_type(&self, cx: &CodegenCx) -> Type {
449 CastTarget::Uniform(u) => u.llvm_type(cx),
450 CastTarget::Pair(a, b) => {
460 /// Information about how to pass an argument to,
461 /// or return a value from, a function, under some ABI.
463 pub struct ArgType<'tcx> {
464 pub layout: TyLayout<'tcx>,
466 /// Dummy argument, which is emitted before the real argument.
467 pub pad: Option<Reg>,
472 impl<'a, 'tcx> ArgType<'tcx> {
473 fn new(layout: TyLayout<'tcx>) -> ArgType<'tcx> {
477 mode: PassMode::Direct(ArgAttributes::new()),
481 pub fn make_indirect(&mut self) {
482 assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new()));
484 // Start with fresh attributes for the pointer.
485 let mut attrs = ArgAttributes::new();
487 // For non-immediate arguments the callee gets its own copy of
488 // the value on the stack, so there are no aliases. It's also
489 // program-invisible so can't possibly capture
490 attrs.set(ArgAttribute::NoAlias)
491 .set(ArgAttribute::NoCapture)
492 .set(ArgAttribute::NonNull);
493 attrs.pointee_size = self.layout.size;
494 // FIXME(eddyb) We should be doing this, but at least on
495 // i686-pc-windows-msvc, it results in wrong stack offsets.
496 // attrs.pointee_align = Some(self.layout.align);
498 self.mode = PassMode::Indirect(attrs);
501 pub fn make_indirect_byval(&mut self) {
502 self.make_indirect();
504 PassMode::Indirect(ref mut attrs) => {
505 attrs.set(ArgAttribute::ByVal);
511 pub fn extend_integer_width_to(&mut self, bits: u64) {
512 // Only integers have signedness
513 if let layout::Abi::Scalar(ref scalar) = self.layout.abi {
514 if let layout::Int(i, signed) = scalar.value {
515 if i.size().bits() < bits {
516 if let PassMode::Direct(ref mut attrs) = self.mode {
517 attrs.set(if signed {
528 pub fn cast_to<T: Into<CastTarget>>(&mut self, target: T) {
529 assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new()));
530 self.mode = PassMode::Cast(target.into());
533 pub fn pad_with(&mut self, reg: Reg) {
534 self.pad = Some(reg);
537 pub fn is_indirect(&self) -> bool {
539 PassMode::Indirect(_) => true,
544 pub fn is_ignore(&self) -> bool {
545 self.mode == PassMode::Ignore
548 /// Get the LLVM type for a place of the original Rust type of
549 /// this argument/return, i.e. the result of `type_of::type_of`.
550 pub fn memory_ty(&self, cx: &CodegenCx<'a, 'tcx>) -> Type {
551 self.layout.llvm_type(cx)
554 /// Store a direct/indirect value described by this ArgType into a
555 /// place for the original Rust type of this argument/return.
556 /// Can be used for both storing formal arguments into Rust variables
557 /// or results of call/invoke instructions into their destinations.
558 pub fn store(&self, bx: &Builder<'a, 'tcx>, val: ValueRef, dst: PlaceRef<'tcx>) {
559 if self.is_ignore() {
563 if self.is_indirect() {
564 OperandValue::Ref(val, self.layout.align).store(bx, dst)
565 } else if let PassMode::Cast(cast) = self.mode {
566 // FIXME(eddyb): Figure out when the simpler Store is safe, clang
567 // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
568 let can_store_through_cast_ptr = false;
569 if can_store_through_cast_ptr {
570 let cast_dst = bx.pointercast(dst.llval, cast.llvm_type(cx).ptr_to());
571 bx.store(val, cast_dst, self.layout.align);
573 // The actual return type is a struct, but the ABI
574 // adaptation code has cast it into some scalar type. The
575 // code that follows is the only reliable way I have
576 // found to do a transform like i64 -> {i32,i32}.
577 // Basically we dump the data onto the stack then memcpy it.
579 // Other approaches I tried:
580 // - Casting rust ret pointer to the foreign type and using Store
581 // is (a) unsafe if size of foreign type > size of rust type and
582 // (b) runs afoul of strict aliasing rules, yielding invalid
583 // assembly under -O (specifically, the store gets removed).
584 // - Truncating foreign type to correct integral type and then
585 // bitcasting to the struct type yields invalid cast errors.
587 // We instead thus allocate some scratch space...
588 let scratch_size = cast.size(cx);
589 let scratch_align = cast.align(cx);
590 let llscratch = bx.alloca(cast.llvm_type(cx), "abi_cast", scratch_align);
591 bx.lifetime_start(llscratch, scratch_size);
593 // ...where we first store the value...
594 bx.store(val, llscratch, scratch_align);
596 // ...and then memcpy it to the intended destination.
597 base::call_memcpy(bx,
598 bx.pointercast(dst.llval, Type::i8p(cx)),
599 bx.pointercast(llscratch, Type::i8p(cx)),
600 C_usize(cx, self.layout.size.bytes()),
601 self.layout.align.min(scratch_align));
603 bx.lifetime_end(llscratch, scratch_size);
606 OperandValue::Immediate(val).store(bx, dst);
610 pub fn store_fn_arg(&self, bx: &Builder<'a, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx>) {
612 let val = llvm::get_param(bx.llfn(), *idx as c_uint);
617 PassMode::Ignore => {},
618 PassMode::Pair(..) => {
619 OperandValue::Pair(next(), next()).store(bx, dst);
621 PassMode::Direct(_) | PassMode::Indirect(_) | PassMode::Cast(_) => {
622 self.store(bx, next(), dst);
628 /// Metadata describing how the arguments to a native function
629 /// should be passed in order to respect the native ABI.
631 /// I will do my best to describe this structure, but these
632 /// comments are reverse-engineered and may be inaccurate. -NDM
634 pub struct FnType<'tcx> {
635 /// The LLVM types of each argument.
636 pub args: Vec<ArgType<'tcx>>,
638 /// LLVM return type.
639 pub ret: ArgType<'tcx>,
643 pub cconv: llvm::CallConv
646 impl<'a, 'tcx> FnType<'tcx> {
647 pub fn of_instance(cx: &CodegenCx<'a, 'tcx>, instance: &ty::Instance<'tcx>)
649 let fn_ty = instance.ty(cx.tcx);
650 let sig = ty_fn_sig(cx, fn_ty);
651 let sig = cx.tcx.erase_late_bound_regions_and_normalize(&sig);
652 FnType::new(cx, sig, &[])
655 pub fn new(cx: &CodegenCx<'a, 'tcx>,
656 sig: ty::FnSig<'tcx>,
657 extra_args: &[Ty<'tcx>]) -> FnType<'tcx> {
658 let mut fn_ty = FnType::unadjusted(cx, sig, extra_args);
659 fn_ty.adjust_for_abi(cx, sig.abi);
663 pub fn new_vtable(cx: &CodegenCx<'a, 'tcx>,
664 sig: ty::FnSig<'tcx>,
665 extra_args: &[Ty<'tcx>]) -> FnType<'tcx> {
666 let mut fn_ty = FnType::unadjusted(cx, sig, extra_args);
667 // Don't pass the vtable, it's not an argument of the virtual fn.
669 let self_arg = &mut fn_ty.args[0];
670 match self_arg.mode {
671 PassMode::Pair(data_ptr, _) => {
672 self_arg.mode = PassMode::Direct(data_ptr);
674 _ => bug!("FnType::new_vtable: non-pair self {:?}", self_arg)
677 let pointee = self_arg.layout.ty.builtin_deref(true)
679 bug!("FnType::new_vtable: non-pointer self {:?}", self_arg)
681 let fat_ptr_ty = cx.tcx.mk_mut_ptr(pointee);
682 self_arg.layout = cx.layout_of(fat_ptr_ty).field(cx, 0);
684 fn_ty.adjust_for_abi(cx, sig.abi);
688 pub fn unadjusted(cx: &CodegenCx<'a, 'tcx>,
689 sig: ty::FnSig<'tcx>,
690 extra_args: &[Ty<'tcx>]) -> FnType<'tcx> {
691 debug!("FnType::unadjusted({:?}, {:?})", sig, extra_args);
694 let cconv = match cx.sess().target.target.adjust_abi(sig.abi) {
695 RustIntrinsic | PlatformIntrinsic |
696 Rust | RustCall => llvm::CCallConv,
698 // It's the ABI's job to select this, not us.
699 System => bug!("system abi should be selected elsewhere"),
701 Stdcall => llvm::X86StdcallCallConv,
702 Fastcall => llvm::X86FastcallCallConv,
703 Vectorcall => llvm::X86_VectorCall,
704 Thiscall => llvm::X86_ThisCall,
705 C => llvm::CCallConv,
706 Unadjusted => llvm::CCallConv,
707 Win64 => llvm::X86_64_Win64,
708 SysV64 => llvm::X86_64_SysV,
709 Aapcs => llvm::ArmAapcsCallConv,
710 PtxKernel => llvm::PtxKernel,
711 Msp430Interrupt => llvm::Msp430Intr,
712 X86Interrupt => llvm::X86_Intr,
714 // These API constants ought to be more specific...
715 Cdecl => llvm::CCallConv,
718 let mut inputs = sig.inputs();
719 let extra_args = if sig.abi == RustCall {
720 assert!(!sig.variadic && extra_args.is_empty());
722 match sig.inputs().last().unwrap().sty {
723 ty::TyTuple(ref tupled_arguments, _) => {
724 inputs = &sig.inputs()[0..sig.inputs().len() - 1];
728 bug!("argument to function with \"rust-call\" ABI \
733 assert!(sig.variadic || extra_args.is_empty());
737 let target = &cx.sess().target.target;
738 let win_x64_gnu = target.target_os == "windows"
739 && target.arch == "x86_64"
740 && target.target_env == "gnu";
741 let linux_s390x = target.target_os == "linux"
742 && target.arch == "s390x"
743 && target.target_env == "gnu";
744 let rust_abi = match sig.abi {
745 RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true,
749 // Handle safe Rust thin and fat pointers.
750 let adjust_for_rust_scalar = |attrs: &mut ArgAttributes,
751 scalar: &layout::Scalar,
752 layout: TyLayout<'tcx>,
755 // Booleans are always an i1 that needs to be zero-extended.
756 if scalar.is_bool() {
757 attrs.set(ArgAttribute::ZExt);
761 // Only pointer types handled below.
762 if scalar.value != layout::Pointer {
766 if scalar.valid_range.start < scalar.valid_range.end {
767 if scalar.valid_range.start > 0 {
768 attrs.set(ArgAttribute::NonNull);
772 if let Some(pointee) = layout.pointee_info_at(cx, offset) {
773 if let Some(kind) = pointee.safe {
774 attrs.pointee_size = pointee.size;
775 attrs.pointee_align = Some(pointee.align);
777 // HACK(eddyb) LLVM inserts `llvm.assume` calls when inlining functions
778 // with align attributes, and those calls later block optimizations.
780 attrs.pointee_align = None;
783 // `Box` pointer parameters never alias because ownership is transferred
784 // `&mut` pointer parameters never alias other parameters,
785 // or mutable global data
787 // `&T` where `T` contains no `UnsafeCell<U>` is immutable,
788 // and can be marked as both `readonly` and `noalias`, as
789 // LLVM's definition of `noalias` is based solely on memory
790 // dependencies rather than pointer equality
791 let no_alias = match kind {
792 PointerKind::Shared => false,
793 PointerKind::UniqueOwned => true,
794 PointerKind::Frozen |
795 PointerKind::UniqueBorrowed => !is_return
798 attrs.set(ArgAttribute::NoAlias);
801 if kind == PointerKind::Frozen && !is_return {
802 attrs.set(ArgAttribute::ReadOnly);
808 let arg_of = |ty: Ty<'tcx>, is_return: bool| {
809 let mut arg = ArgType::new(cx.layout_of(ty));
810 if arg.layout.is_zst() {
811 // For some forsaken reason, x86_64-pc-windows-gnu
812 // doesn't ignore zero-sized struct arguments.
813 // The same is true for s390x-unknown-linux-gnu.
814 if is_return || rust_abi || (!win_x64_gnu && !linux_s390x) {
815 arg.mode = PassMode::Ignore;
819 // FIXME(eddyb) other ABIs don't have logic for scalar pairs.
820 if !is_return && rust_abi {
821 if let layout::Abi::ScalarPair(ref a, ref b) = arg.layout.abi {
822 let mut a_attrs = ArgAttributes::new();
823 let mut b_attrs = ArgAttributes::new();
824 adjust_for_rust_scalar(&mut a_attrs,
829 adjust_for_rust_scalar(&mut b_attrs,
832 a.value.size(cx).abi_align(b.value.align(cx)),
834 arg.mode = PassMode::Pair(a_attrs, b_attrs);
839 if let layout::Abi::Scalar(ref scalar) = arg.layout.abi {
840 if let PassMode::Direct(ref mut attrs) = arg.mode {
841 adjust_for_rust_scalar(attrs,
853 ret: arg_of(sig.output(), true),
854 args: inputs.iter().chain(extra_args.iter()).map(|ty| {
857 variadic: sig.variadic,
862 fn adjust_for_abi(&mut self,
863 cx: &CodegenCx<'a, 'tcx>,
865 if abi == Abi::Unadjusted { return }
867 if abi == Abi::Rust || abi == Abi::RustCall ||
868 abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
869 let fixup = |arg: &mut ArgType<'tcx>| {
870 if arg.is_ignore() { return; }
872 match arg.layout.abi {
873 layout::Abi::Aggregate { .. } => {}
875 // This is a fun case! The gist of what this is doing is
876 // that we want callers and callees to always agree on the
877 // ABI of how they pass SIMD arguments. If we were to *not*
878 // make these arguments indirect then they'd be immediates
879 // in LLVM, which means that they'd used whatever the
880 // appropriate ABI is for the callee and the caller. That
881 // means, for example, if the caller doesn't have AVX
882 // enabled but the callee does, then passing an AVX argument
883 // across this boundary would cause corrupt data to show up.
885 // This problem is fixed by unconditionally passing SIMD
886 // arguments through memory between callers and callees
887 // which should get them all to agree on ABI regardless of
888 // target feature sets. Some more information about this
889 // issue can be found in #44367.
891 // Note that the platform intrinsic ABI is exempt here as
892 // that's how we connect up to LLVM and it's unstable
893 // anyway, we control all calls to it in libstd.
894 layout::Abi::Vector { .. } if abi != Abi::PlatformIntrinsic => {
902 let size = arg.layout.size;
903 if size > layout::Pointer.size(cx) {
906 // We want to pass small aggregates as immediates, but using
907 // a LLVM aggregate type for this leads to bad optimizations,
908 // so we pick an appropriately sized integer type instead.
910 kind: RegKind::Integer,
915 fixup(&mut self.ret);
916 for arg in &mut self.args {
919 if let PassMode::Indirect(ref mut attrs) = self.ret.mode {
920 attrs.set(ArgAttribute::StructRet);
925 match &cx.sess().target.target.arch[..] {
927 let flavor = if abi == Abi::Fastcall {
928 cabi_x86::Flavor::Fastcall
930 cabi_x86::Flavor::General
932 cabi_x86::compute_abi_info(cx, self, flavor);
934 "x86_64" => if abi == Abi::SysV64 {
935 cabi_x86_64::compute_abi_info(cx, self);
936 } else if abi == Abi::Win64 || cx.sess().target.target.options.is_like_windows {
937 cabi_x86_win64::compute_abi_info(self);
939 cabi_x86_64::compute_abi_info(cx, self);
941 "aarch64" => cabi_aarch64::compute_abi_info(cx, self),
942 "arm" => cabi_arm::compute_abi_info(cx, self),
943 "mips" => cabi_mips::compute_abi_info(cx, self),
944 "mips64" => cabi_mips64::compute_abi_info(cx, self),
945 "powerpc" => cabi_powerpc::compute_abi_info(cx, self),
946 "powerpc64" => cabi_powerpc64::compute_abi_info(cx, self),
947 "s390x" => cabi_s390x::compute_abi_info(cx, self),
948 "asmjs" => cabi_asmjs::compute_abi_info(cx, self),
949 "wasm32" => cabi_asmjs::compute_abi_info(cx, self),
950 "msp430" => cabi_msp430::compute_abi_info(self),
951 "sparc" => cabi_sparc::compute_abi_info(cx, self),
952 "sparc64" => cabi_sparc64::compute_abi_info(cx, self),
953 "nvptx" => cabi_nvptx::compute_abi_info(self),
954 "nvptx64" => cabi_nvptx64::compute_abi_info(self),
955 "hexagon" => cabi_hexagon::compute_abi_info(self),
956 a => cx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a))
959 if let PassMode::Indirect(ref mut attrs) = self.ret.mode {
960 attrs.set(ArgAttribute::StructRet);
964 pub fn llvm_type(&self, cx: &CodegenCx<'a, 'tcx>) -> Type {
965 let mut llargument_tys = Vec::new();
967 let llreturn_ty = match self.ret.mode {
968 PassMode::Ignore => Type::void(cx),
969 PassMode::Direct(_) | PassMode::Pair(..) => {
970 self.ret.layout.immediate_llvm_type(cx)
972 PassMode::Cast(cast) => cast.llvm_type(cx),
973 PassMode::Indirect(_) => {
974 llargument_tys.push(self.ret.memory_ty(cx).ptr_to());
979 for arg in &self.args {
981 if let Some(ty) = arg.pad {
982 llargument_tys.push(ty.llvm_type(cx));
985 let llarg_ty = match arg.mode {
986 PassMode::Ignore => continue,
987 PassMode::Direct(_) => arg.layout.immediate_llvm_type(cx),
988 PassMode::Pair(..) => {
989 llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0));
990 llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1));
993 PassMode::Cast(cast) => cast.llvm_type(cx),
994 PassMode::Indirect(_) => arg.memory_ty(cx).ptr_to(),
996 llargument_tys.push(llarg_ty);
1000 Type::variadic_func(&llargument_tys, &llreturn_ty)
1002 Type::func(&llargument_tys, &llreturn_ty)
1006 pub fn apply_attrs_llfn(&self, llfn: ValueRef) {
1008 let mut apply = |attrs: &ArgAttributes| {
1009 attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn);
1012 match self.ret.mode {
1013 PassMode::Direct(ref attrs) => {
1014 attrs.apply_llfn(llvm::AttributePlace::ReturnValue, llfn);
1016 PassMode::Indirect(ref attrs) => apply(attrs),
1019 for arg in &self.args {
1020 if arg.pad.is_some() {
1021 apply(&ArgAttributes::new());
1024 PassMode::Ignore => {}
1025 PassMode::Direct(ref attrs) |
1026 PassMode::Indirect(ref attrs) => apply(attrs),
1027 PassMode::Pair(ref a, ref b) => {
1031 PassMode::Cast(_) => apply(&ArgAttributes::new()),
1036 pub fn apply_attrs_callsite(&self, callsite: ValueRef) {
1038 let mut apply = |attrs: &ArgAttributes| {
1039 attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite);
1042 match self.ret.mode {
1043 PassMode::Direct(ref attrs) => {
1044 attrs.apply_callsite(llvm::AttributePlace::ReturnValue, callsite);
1046 PassMode::Indirect(ref attrs) => apply(attrs),
1049 for arg in &self.args {
1050 if arg.pad.is_some() {
1051 apply(&ArgAttributes::new());
1054 PassMode::Ignore => {}
1055 PassMode::Direct(ref attrs) |
1056 PassMode::Indirect(ref attrs) => apply(attrs),
1057 PassMode::Pair(ref a, ref b) => {
1061 PassMode::Cast(_) => apply(&ArgAttributes::new()),
1065 if self.cconv != llvm::CCallConv {
1066 llvm::SetInstructionCallConv(callsite, self.cconv);