]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/abi.rs
Rollup merge of #47193 - cramertj:result-opts, r=TimNN
[rust.git] / src / librustc_trans / abi.rs
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.
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 use llvm::{self, ValueRef, AttributePlace};
12 use base;
13 use builder::Builder;
14 use common::{ty_fn_sig, C_usize};
15 use context::CodegenCx;
16 use cabi_x86;
17 use cabi_x86_64;
18 use cabi_x86_win64;
19 use cabi_arm;
20 use cabi_aarch64;
21 use cabi_powerpc;
22 use cabi_powerpc64;
23 use cabi_s390x;
24 use cabi_mips;
25 use cabi_mips64;
26 use cabi_asmjs;
27 use cabi_msp430;
28 use cabi_sparc;
29 use cabi_sparc64;
30 use cabi_nvptx;
31 use cabi_nvptx64;
32 use cabi_hexagon;
33 use mir::place::PlaceRef;
34 use mir::operand::OperandValue;
35 use type_::Type;
36 use type_of::{LayoutLlvmExt, PointerKind};
37
38 use rustc::ty::{self, Ty};
39 use rustc::ty::layout::{self, Align, Size, TyLayout};
40 use rustc::ty::layout::{HasDataLayout, LayoutOf};
41
42 use libc::c_uint;
43 use std::{cmp, iter};
44
45 pub use syntax::abi::Abi;
46 pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
47
48 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
49 pub enum PassMode {
50     /// Ignore the argument (useful for empty struct).
51     Ignore,
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.
58     Cast(CastTarget),
59     /// Pass the argument indirectly via a hidden pointer.
60     Indirect(ArgAttributes),
61 }
62
63 // Hack to disable non_upper_case_globals only for the bitflags! and not for the rest
64 // of this module
65 pub use self::attr_impl::ArgAttribute;
66
67 #[allow(non_upper_case_globals)]
68 #[allow(unused)]
69 mod attr_impl {
70     // The subset of llvm::Attribute needed for arguments, packed into a bitfield.
71     bitflags! {
72         #[derive(Default)]
73         pub struct ArgAttribute: u16 {
74             const ByVal     = 1 << 0;
75             const NoAlias   = 1 << 1;
76             const NoCapture = 1 << 2;
77             const NonNull   = 1 << 3;
78             const ReadOnly  = 1 << 4;
79             const SExt      = 1 << 5;
80             const StructRet = 1 << 6;
81             const ZExt      = 1 << 7;
82             const InReg     = 1 << 8;
83         }
84     }
85 }
86
87 macro_rules! for_each_kind {
88     ($flags: ident, $f: ident, $($kind: ident),+) => ({
89         $(if $flags.contains(ArgAttribute::$kind) { $f(llvm::Attribute::$kind) })+
90     })
91 }
92
93 impl ArgAttribute {
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)
97     }
98 }
99
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,
105     pointee_size: Size,
106     pointee_align: Option<Align>
107 }
108
109 impl ArgAttributes {
110     fn new() -> Self {
111         ArgAttributes {
112             regular: ArgAttribute::default(),
113             pointee_size: Size::from_bytes(0),
114             pointee_align: None,
115         }
116     }
117
118     pub fn set(&mut self, attr: ArgAttribute) -> &mut Self {
119         self.regular = self.regular | attr;
120         self
121     }
122
123     pub fn contains(&self, attr: ArgAttribute) -> bool {
124         self.regular.contains(attr)
125     }
126
127     pub fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) {
128         let mut regular = self.regular;
129         unsafe {
130             let deref = self.pointee_size.bytes();
131             if deref != 0 {
132                 if regular.contains(ArgAttribute::NonNull) {
133                     llvm::LLVMRustAddDereferenceableAttr(llfn,
134                                                          idx.as_uint(),
135                                                          deref);
136                 } else {
137                     llvm::LLVMRustAddDereferenceableOrNullAttr(llfn,
138                                                                idx.as_uint(),
139                                                                deref);
140                 }
141                 regular -= ArgAttribute::NonNull;
142             }
143             if let Some(align) = self.pointee_align {
144                 llvm::LLVMRustAddAlignmentAttr(llfn,
145                                                idx.as_uint(),
146                                                align.abi() as u32);
147             }
148             regular.for_each_kind(|attr| attr.apply_llfn(idx, llfn));
149         }
150     }
151
152     pub fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef) {
153         let mut regular = self.regular;
154         unsafe {
155             let deref = self.pointee_size.bytes();
156             if deref != 0 {
157                 if regular.contains(ArgAttribute::NonNull) {
158                     llvm::LLVMRustAddDereferenceableCallSiteAttr(callsite,
159                                                                  idx.as_uint(),
160                                                                  deref);
161                 } else {
162                     llvm::LLVMRustAddDereferenceableOrNullCallSiteAttr(callsite,
163                                                                        idx.as_uint(),
164                                                                        deref);
165                 }
166                 regular -= ArgAttribute::NonNull;
167             }
168             if let Some(align) = self.pointee_align {
169                 llvm::LLVMRustAddAlignmentCallSiteAttr(callsite,
170                                                        idx.as_uint(),
171                                                        align.abi() as u32);
172             }
173             regular.for_each_kind(|attr| attr.apply_callsite(idx, callsite));
174         }
175     }
176 }
177 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
178 pub enum RegKind {
179     Integer,
180     Float,
181     Vector
182 }
183
184 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
185 pub struct Reg {
186     pub kind: RegKind,
187     pub size: Size,
188 }
189
190 macro_rules! reg_ctor {
191     ($name:ident, $kind:ident, $bits:expr) => {
192         pub fn $name() -> Reg {
193             Reg {
194                 kind: RegKind::$kind,
195                 size: Size::from_bits($bits)
196             }
197         }
198     }
199 }
200
201 impl Reg {
202     reg_ctor!(i8, Integer, 8);
203     reg_ctor!(i16, Integer, 16);
204     reg_ctor!(i32, Integer, 32);
205     reg_ctor!(i64, Integer, 64);
206
207     reg_ctor!(f32, Float, 32);
208     reg_ctor!(f64, Float, 64);
209 }
210
211 impl Reg {
212     pub fn align(&self, cx: &CodegenCx) -> Align {
213         let dl = cx.data_layout();
214         match self.kind {
215             RegKind::Integer => {
216                 match self.size.bits() {
217                     1 => dl.i1_align,
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)
224                 }
225             }
226             RegKind::Float => {
227                 match self.size.bits() {
228                     32 => dl.f32_align,
229                     64 => dl.f64_align,
230                     _ => bug!("unsupported float: {:?}", self)
231                 }
232             }
233             RegKind::Vector => dl.vector_align(self.size)
234         }
235     }
236
237     pub fn llvm_type(&self, cx: &CodegenCx) -> Type {
238         match self.kind {
239             RegKind::Integer => Type::ix(cx, self.size.bits()),
240             RegKind::Float => {
241                 match self.size.bits() {
242                     32 => Type::f32(cx),
243                     64 => Type::f64(cx),
244                     _ => bug!("unsupported float: {:?}", self)
245                 }
246             }
247             RegKind::Vector => {
248                 Type::vector(&Type::i8(cx), self.size.bytes())
249             }
250         }
251     }
252 }
253
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)]
257 pub struct Uniform {
258     pub unit: Reg,
259
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
266     pub total: Size,
267 }
268
269 impl From<Reg> for Uniform {
270     fn from(unit: Reg) -> Uniform {
271         Uniform {
272             unit,
273             total: unit.size
274         }
275     }
276 }
277
278 impl Uniform {
279     pub fn align(&self, cx: &CodegenCx) -> Align {
280         self.unit.align(cx)
281     }
282
283     pub fn llvm_type(&self, cx: &CodegenCx) -> Type {
284         let llunit = self.unit.llvm_type(cx);
285
286         if self.total <= self.unit.size {
287             return llunit;
288         }
289
290         let count = self.total.bytes() / self.unit.size.bytes();
291         let rem_bytes = self.total.bytes() % self.unit.size.bytes();
292
293         if rem_bytes == 0 {
294             return Type::array(&llunit, count);
295         }
296
297         // Only integers can be really split further.
298         assert_eq!(self.unit.kind, RegKind::Integer);
299
300         let args: Vec<_> = (0..count).map(|_| llunit)
301             .chain(iter::once(Type::ix(cx, rem_bytes * 8)))
302             .collect();
303
304         Type::struct_(cx, &args, false)
305     }
306 }
307
308 pub trait LayoutExt<'tcx> {
309     fn is_aggregate(&self) -> bool;
310     fn homogeneous_aggregate<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Option<Reg>;
311 }
312
313 impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> {
314     fn is_aggregate(&self) -> bool {
315         match self.abi {
316             layout::Abi::Uninhabited |
317             layout::Abi::Scalar(_) |
318             layout::Abi::Vector { .. } => false,
319             layout::Abi::ScalarPair(..) |
320             layout::Abi::Aggregate { .. } => true
321         }
322     }
323
324     fn homogeneous_aggregate<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Option<Reg> {
325         match self.abi {
326             layout::Abi::Uninhabited => None,
327
328             // The primitive for this algorithm.
329             layout::Abi::Scalar(ref scalar) => {
330                 let kind = match scalar.value {
331                     layout::Int(..) |
332                     layout::Pointer => RegKind::Integer,
333                     layout::F32 |
334                     layout::F64 => RegKind::Float
335                 };
336                 Some(Reg {
337                     kind,
338                     size: self.size
339                 })
340             }
341
342             layout::Abi::Vector { .. } => {
343                 Some(Reg {
344                     kind: RegKind::Vector,
345                     size: self.size
346                 })
347             }
348
349             layout::Abi::ScalarPair(..) |
350             layout::Abi::Aggregate { .. } => {
351                 let mut total = Size::from_bytes(0);
352                 let mut result = None;
353
354                 let is_union = match self.fields {
355                     layout::FieldPlacement::Array { count, .. } => {
356                         if count > 0 {
357                             return self.field(cx, 0).homogeneous_aggregate(cx);
358                         } else {
359                             return None;
360                         }
361                     }
362                     layout::FieldPlacement::Union(_) => true,
363                     layout::FieldPlacement::Arbitrary { .. } => false
364                 };
365
366                 for i in 0..self.fields.count() {
367                     if !is_union && total != self.fields.offset(i) {
368                         return None;
369                     }
370
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)) => {
377                             result = Some(unit);
378                         }
379                         // For all following fields, the unit must be the same.
380                         (Some(prev_unit), Some(unit)) => {
381                             if prev_unit != unit {
382                                 return None;
383                             }
384                         }
385                     }
386
387                     // Keep track of the offset (without padding).
388                     let size = field.size;
389                     if is_union {
390                         total = cmp::max(total, size);
391                     } else {
392                         total += size;
393                     }
394                 }
395
396                 // There needs to be no padding.
397                 if total != self.size {
398                     None
399                 } else {
400                     result
401                 }
402             }
403         }
404     }
405 }
406
407 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
408 pub enum CastTarget {
409     Uniform(Uniform),
410     Pair(Reg, Reg)
411 }
412
413 impl From<Reg> for CastTarget {
414     fn from(unit: Reg) -> CastTarget {
415         CastTarget::Uniform(Uniform::from(unit))
416     }
417 }
418
419 impl From<Uniform> for CastTarget {
420     fn from(uniform: Uniform) -> CastTarget {
421         CastTarget::Uniform(uniform)
422     }
423 }
424
425 impl CastTarget {
426     pub fn size(&self, cx: &CodegenCx) -> Size {
427         match *self {
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))
432             }
433         }
434     }
435
436     pub fn align(&self, cx: &CodegenCx) -> Align {
437         match *self {
438             CastTarget::Uniform(u) => u.align(cx),
439             CastTarget::Pair(a, b) => {
440                 cx.data_layout().aggregate_align
441                     .max(a.align(cx))
442                     .max(b.align(cx))
443             }
444         }
445     }
446
447     pub fn llvm_type(&self, cx: &CodegenCx) -> Type {
448         match *self {
449             CastTarget::Uniform(u) => u.llvm_type(cx),
450             CastTarget::Pair(a, b) => {
451                 Type::struct_(cx, &[
452                     a.llvm_type(cx),
453                     b.llvm_type(cx)
454                 ], false)
455             }
456         }
457     }
458 }
459
460 /// Information about how to pass an argument to,
461 /// or return a value from, a function, under some ABI.
462 #[derive(Debug)]
463 pub struct ArgType<'tcx> {
464     pub layout: TyLayout<'tcx>,
465
466     /// Dummy argument, which is emitted before the real argument.
467     pub pad: Option<Reg>,
468
469     pub mode: PassMode,
470 }
471
472 impl<'a, 'tcx> ArgType<'tcx> {
473     fn new(layout: TyLayout<'tcx>) -> ArgType<'tcx> {
474         ArgType {
475             layout,
476             pad: None,
477             mode: PassMode::Direct(ArgAttributes::new()),
478         }
479     }
480
481     pub fn make_indirect(&mut self) {
482         assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new()));
483
484         // Start with fresh attributes for the pointer.
485         let mut attrs = ArgAttributes::new();
486
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);
497
498         self.mode = PassMode::Indirect(attrs);
499     }
500
501     pub fn make_indirect_byval(&mut self) {
502         self.make_indirect();
503         match self.mode {
504             PassMode::Indirect(ref mut attrs) => {
505                 attrs.set(ArgAttribute::ByVal);
506             }
507             _ => bug!()
508         }
509     }
510
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 {
518                             ArgAttribute::SExt
519                         } else {
520                             ArgAttribute::ZExt
521                         });
522                     }
523                 }
524             }
525         }
526     }
527
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());
531     }
532
533     pub fn pad_with(&mut self, reg: Reg) {
534         self.pad = Some(reg);
535     }
536
537     pub fn is_indirect(&self) -> bool {
538         match self.mode {
539             PassMode::Indirect(_) => true,
540             _ => false
541         }
542     }
543
544     pub fn is_ignore(&self) -> bool {
545         self.mode == PassMode::Ignore
546     }
547
548     /// Get the LLVM type for an 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)
552     }
553
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() {
560             return;
561         }
562         let cx = bx.cx;
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);
572             } else {
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.
578                 //
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.
586
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);
592
593                 // ...where we first store the value...
594                 bx.store(val, llscratch, scratch_align);
595
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));
602
603                 bx.lifetime_end(llscratch, scratch_size);
604             }
605         } else {
606             OperandValue::Immediate(val).store(bx, dst);
607         }
608     }
609
610     pub fn store_fn_arg(&self, bx: &Builder<'a, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx>) {
611         let mut next = || {
612             let val = llvm::get_param(bx.llfn(), *idx as c_uint);
613             *idx += 1;
614             val
615         };
616         match self.mode {
617             PassMode::Ignore => {},
618             PassMode::Pair(..) => {
619                 OperandValue::Pair(next(), next()).store(bx, dst);
620             }
621             PassMode::Direct(_) | PassMode::Indirect(_) | PassMode::Cast(_) => {
622                 self.store(bx, next(), dst);
623             }
624         }
625     }
626 }
627
628 /// Metadata describing how the arguments to a native function
629 /// should be passed in order to respect the native ABI.
630 ///
631 /// I will do my best to describe this structure, but these
632 /// comments are reverse-engineered and may be inaccurate. -NDM
633 #[derive(Debug)]
634 pub struct FnType<'tcx> {
635     /// The LLVM types of each argument.
636     pub args: Vec<ArgType<'tcx>>,
637
638     /// LLVM return type.
639     pub ret: ArgType<'tcx>,
640
641     pub variadic: bool,
642
643     pub cconv: llvm::CallConv
644 }
645
646 impl<'a, 'tcx> FnType<'tcx> {
647     pub fn of_instance(cx: &CodegenCx<'a, 'tcx>, instance: &ty::Instance<'tcx>)
648                        -> Self {
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, &[])
653     }
654
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);
660         fn_ty
661     }
662
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.
668         {
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);
673                 }
674                 _ => bug!("FnType::new_vtable: non-pair self {:?}", self_arg)
675             }
676
677             let pointee = self_arg.layout.ty.builtin_deref(true, ty::NoPreference)
678                 .unwrap_or_else(|| {
679                     bug!("FnType::new_vtable: non-pointer self {:?}", self_arg)
680                 }).ty;
681             let fat_ptr_ty = cx.tcx.mk_mut_ptr(pointee);
682             self_arg.layout = cx.layout_of(fat_ptr_ty).field(cx, 0);
683         }
684         fn_ty.adjust_for_abi(cx, sig.abi);
685         fn_ty
686     }
687
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);
692
693         use self::Abi::*;
694         let cconv = match cx.sess().target.target.adjust_abi(sig.abi) {
695             RustIntrinsic | PlatformIntrinsic |
696             Rust | RustCall => llvm::CCallConv,
697
698             // It's the ABI's job to select this, not us.
699             System => bug!("system abi should be selected elsewhere"),
700
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,
713
714             // These API constants ought to be more specific...
715             Cdecl => llvm::CCallConv,
716         };
717
718         let mut inputs = sig.inputs();
719         let extra_args = if sig.abi == RustCall {
720             assert!(!sig.variadic && extra_args.is_empty());
721
722             match sig.inputs().last().unwrap().sty {
723                 ty::TyTuple(ref tupled_arguments, _) => {
724                     inputs = &sig.inputs()[0..sig.inputs().len() - 1];
725                     tupled_arguments
726                 }
727                 _ => {
728                     bug!("argument to function with \"rust-call\" ABI \
729                           is not a tuple");
730                 }
731             }
732         } else {
733             assert!(sig.variadic || extra_args.is_empty());
734             extra_args
735         };
736
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,
746             _ => false
747         };
748
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>,
753                                       offset: Size,
754                                       is_return: bool| {
755             // Booleans are always an i1 that needs to be zero-extended.
756             if scalar.is_bool() {
757                 attrs.set(ArgAttribute::ZExt);
758                 return;
759             }
760
761             // Only pointer types handled below.
762             if scalar.value != layout::Pointer {
763                 return;
764             }
765
766             if scalar.valid_range.start < scalar.valid_range.end {
767                 if scalar.valid_range.start > 0 {
768                     attrs.set(ArgAttribute::NonNull);
769                 }
770             }
771
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);
776
777                     // HACK(eddyb) LLVM inserts `llvm.assume` calls when inlining functions
778                     // with align attributes, and those calls later block optimizations.
779                     if !is_return {
780                         attrs.pointee_align = None;
781                     }
782
783                     // `Box` pointer parameters never alias because ownership is transferred
784                     // `&mut` pointer parameters never alias other parameters,
785                     // or mutable global data
786                     //
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
796                     };
797                     if no_alias {
798                         attrs.set(ArgAttribute::NoAlias);
799                     }
800
801                     if kind == PointerKind::Frozen && !is_return {
802                         attrs.set(ArgAttribute::ReadOnly);
803                     }
804                 }
805             }
806         };
807
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;
816                 }
817             }
818
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,
825                                            a,
826                                            arg.layout,
827                                            Size::from_bytes(0),
828                                            false);
829                     adjust_for_rust_scalar(&mut b_attrs,
830                                            b,
831                                            arg.layout,
832                                            a.value.size(cx).abi_align(b.value.align(cx)),
833                                            false);
834                     arg.mode = PassMode::Pair(a_attrs, b_attrs);
835                     return arg;
836                 }
837             }
838
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,
842                                            scalar,
843                                            arg.layout,
844                                            Size::from_bytes(0),
845                                            is_return);
846                 }
847             }
848
849             arg
850         };
851
852         FnType {
853             ret: arg_of(sig.output(), true),
854             args: inputs.iter().chain(extra_args.iter()).map(|ty| {
855                 arg_of(ty, false)
856             }).collect(),
857             variadic: sig.variadic,
858             cconv,
859         }
860     }
861
862     fn adjust_for_abi(&mut self,
863                       cx: &CodegenCx<'a, 'tcx>,
864                       abi: Abi) {
865         if abi == Abi::Unadjusted { return }
866
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; }
871
872                 match arg.layout.abi {
873                     layout::Abi::Aggregate { .. } => {}
874                     _ => return
875                 }
876
877                 let size = arg.layout.size;
878                 if size > layout::Pointer.size(cx) {
879                     arg.make_indirect();
880                 } else {
881                     // We want to pass small aggregates as immediates, but using
882                     // a LLVM aggregate type for this leads to bad optimizations,
883                     // so we pick an appropriately sized integer type instead.
884                     arg.cast_to(Reg {
885                         kind: RegKind::Integer,
886                         size
887                     });
888                 }
889             };
890             fixup(&mut self.ret);
891             for arg in &mut self.args {
892                 fixup(arg);
893             }
894             if let PassMode::Indirect(ref mut attrs) = self.ret.mode {
895                 attrs.set(ArgAttribute::StructRet);
896             }
897             return;
898         }
899
900         match &cx.sess().target.target.arch[..] {
901             "x86" => {
902                 let flavor = if abi == Abi::Fastcall {
903                     cabi_x86::Flavor::Fastcall
904                 } else {
905                     cabi_x86::Flavor::General
906                 };
907                 cabi_x86::compute_abi_info(cx, self, flavor);
908             },
909             "x86_64" => if abi == Abi::SysV64 {
910                 cabi_x86_64::compute_abi_info(cx, self);
911             } else if abi == Abi::Win64 || cx.sess().target.target.options.is_like_windows {
912                 cabi_x86_win64::compute_abi_info(self);
913             } else {
914                 cabi_x86_64::compute_abi_info(cx, self);
915             },
916             "aarch64" => cabi_aarch64::compute_abi_info(cx, self),
917             "arm" => cabi_arm::compute_abi_info(cx, self),
918             "mips" => cabi_mips::compute_abi_info(cx, self),
919             "mips64" => cabi_mips64::compute_abi_info(cx, self),
920             "powerpc" => cabi_powerpc::compute_abi_info(cx, self),
921             "powerpc64" => cabi_powerpc64::compute_abi_info(cx, self),
922             "s390x" => cabi_s390x::compute_abi_info(cx, self),
923             "asmjs" => cabi_asmjs::compute_abi_info(cx, self),
924             "wasm32" => cabi_asmjs::compute_abi_info(cx, self),
925             "msp430" => cabi_msp430::compute_abi_info(self),
926             "sparc" => cabi_sparc::compute_abi_info(cx, self),
927             "sparc64" => cabi_sparc64::compute_abi_info(cx, self),
928             "nvptx" => cabi_nvptx::compute_abi_info(self),
929             "nvptx64" => cabi_nvptx64::compute_abi_info(self),
930             "hexagon" => cabi_hexagon::compute_abi_info(self),
931             a => cx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a))
932         }
933
934         if let PassMode::Indirect(ref mut attrs) = self.ret.mode {
935             attrs.set(ArgAttribute::StructRet);
936         }
937     }
938
939     pub fn llvm_type(&self, cx: &CodegenCx<'a, 'tcx>) -> Type {
940         let mut llargument_tys = Vec::new();
941
942         let llreturn_ty = match self.ret.mode {
943             PassMode::Ignore => Type::void(cx),
944             PassMode::Direct(_) | PassMode::Pair(..) => {
945                 self.ret.layout.immediate_llvm_type(cx)
946             }
947             PassMode::Cast(cast) => cast.llvm_type(cx),
948             PassMode::Indirect(_) => {
949                 llargument_tys.push(self.ret.memory_ty(cx).ptr_to());
950                 Type::void(cx)
951             }
952         };
953
954         for arg in &self.args {
955             // add padding
956             if let Some(ty) = arg.pad {
957                 llargument_tys.push(ty.llvm_type(cx));
958             }
959
960             let llarg_ty = match arg.mode {
961                 PassMode::Ignore => continue,
962                 PassMode::Direct(_) => arg.layout.immediate_llvm_type(cx),
963                 PassMode::Pair(..) => {
964                     llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0));
965                     llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1));
966                     continue;
967                 }
968                 PassMode::Cast(cast) => cast.llvm_type(cx),
969                 PassMode::Indirect(_) => arg.memory_ty(cx).ptr_to(),
970             };
971             llargument_tys.push(llarg_ty);
972         }
973
974         if self.variadic {
975             Type::variadic_func(&llargument_tys, &llreturn_ty)
976         } else {
977             Type::func(&llargument_tys, &llreturn_ty)
978         }
979     }
980
981     pub fn apply_attrs_llfn(&self, llfn: ValueRef) {
982         let mut i = 0;
983         let mut apply = |attrs: &ArgAttributes| {
984             attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn);
985             i += 1;
986         };
987         match self.ret.mode {
988             PassMode::Direct(ref attrs) => {
989                 attrs.apply_llfn(llvm::AttributePlace::ReturnValue, llfn);
990             }
991             PassMode::Indirect(ref attrs) => apply(attrs),
992             _ => {}
993         }
994         for arg in &self.args {
995             if arg.pad.is_some() {
996                 apply(&ArgAttributes::new());
997             }
998             match arg.mode {
999                 PassMode::Ignore => {}
1000                 PassMode::Direct(ref attrs) |
1001                 PassMode::Indirect(ref attrs) => apply(attrs),
1002                 PassMode::Pair(ref a, ref b) => {
1003                     apply(a);
1004                     apply(b);
1005                 }
1006                 PassMode::Cast(_) => apply(&ArgAttributes::new()),
1007             }
1008         }
1009     }
1010
1011     pub fn apply_attrs_callsite(&self, callsite: ValueRef) {
1012         let mut i = 0;
1013         let mut apply = |attrs: &ArgAttributes| {
1014             attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite);
1015             i += 1;
1016         };
1017         match self.ret.mode {
1018             PassMode::Direct(ref attrs) => {
1019                 attrs.apply_callsite(llvm::AttributePlace::ReturnValue, callsite);
1020             }
1021             PassMode::Indirect(ref attrs) => apply(attrs),
1022             _ => {}
1023         }
1024         for arg in &self.args {
1025             if arg.pad.is_some() {
1026                 apply(&ArgAttributes::new());
1027             }
1028             match arg.mode {
1029                 PassMode::Ignore => {}
1030                 PassMode::Direct(ref attrs) |
1031                 PassMode::Indirect(ref attrs) => apply(attrs),
1032                 PassMode::Pair(ref a, ref b) => {
1033                     apply(a);
1034                     apply(b);
1035                 }
1036                 PassMode::Cast(_) => apply(&ArgAttributes::new()),
1037             }
1038         }
1039
1040         if self.cconv != llvm::CCallConv {
1041             llvm::SetInstructionCallConv(callsite, self.cconv);
1042         }
1043     }
1044 }