]> git.lizzy.rs Git - rust.git/blob - src/librustc_target/abi/call/mod.rs
Integrate PassMode::UnsizedIndirect into PassMode::Indirect.
[rust.git] / src / librustc_target / abi / call / mod.rs
1 // Copyright 2017 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 abi::{self, Abi, Align, FieldPlacement, Size};
12 use abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods};
13 use spec::HasTargetSpec;
14
15 mod aarch64;
16 mod arm;
17 mod asmjs;
18 mod hexagon;
19 mod mips;
20 mod mips64;
21 mod msp430;
22 mod nvptx;
23 mod nvptx64;
24 mod powerpc;
25 mod powerpc64;
26 mod riscv;
27 mod s390x;
28 mod sparc;
29 mod sparc64;
30 mod x86;
31 mod x86_64;
32 mod x86_win64;
33 mod wasm32;
34
35 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
36 pub enum PassMode {
37     /// Ignore the argument (useful for empty struct).
38     Ignore,
39     /// Pass the argument directly.
40     Direct(ArgAttributes),
41     /// Pass a pair's elements directly in two arguments.
42     Pair(ArgAttributes, ArgAttributes),
43     /// Pass the argument after casting it, to either
44     /// a single uniform or a pair of registers.
45     Cast(CastTarget),
46     /// Pass the argument indirectly via a hidden pointer.
47     /// The second value, if any, is for the extra data (vtable or length)
48     /// which indicates that it refers to an unsized rvalue.
49     Indirect(ArgAttributes, Option<ArgAttributes>),
50 }
51
52 // Hack to disable non_upper_case_globals only for the bitflags! and not for the rest
53 // of this module
54 pub use self::attr_impl::ArgAttribute;
55
56 #[allow(non_upper_case_globals)]
57 #[allow(unused)]
58 mod attr_impl {
59     // The subset of llvm::Attribute needed for arguments, packed into a bitfield.
60     bitflags! {
61         #[derive(Default)]
62         pub struct ArgAttribute: u16 {
63             const ByVal     = 1 << 0;
64             const NoAlias   = 1 << 1;
65             const NoCapture = 1 << 2;
66             const NonNull   = 1 << 3;
67             const ReadOnly  = 1 << 4;
68             const SExt      = 1 << 5;
69             const StructRet = 1 << 6;
70             const ZExt      = 1 << 7;
71             const InReg     = 1 << 8;
72         }
73     }
74 }
75
76 /// A compact representation of LLVM attributes (at least those relevant for this module)
77 /// that can be manipulated without interacting with LLVM's Attribute machinery.
78 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
79 pub struct ArgAttributes {
80     pub regular: ArgAttribute,
81     pub pointee_size: Size,
82     pub pointee_align: Option<Align>
83 }
84
85 impl ArgAttributes {
86     pub fn new() -> Self {
87         ArgAttributes {
88             regular: ArgAttribute::default(),
89             pointee_size: Size::ZERO,
90             pointee_align: None,
91         }
92     }
93
94     pub fn set(&mut self, attr: ArgAttribute) -> &mut Self {
95         self.regular |= attr;
96         self
97     }
98
99     pub fn contains(&self, attr: ArgAttribute) -> bool {
100         self.regular.contains(attr)
101     }
102 }
103
104 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
105 pub enum RegKind {
106     Integer,
107     Float,
108     Vector
109 }
110
111 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
112 pub struct Reg {
113     pub kind: RegKind,
114     pub size: Size,
115 }
116
117 macro_rules! reg_ctor {
118     ($name:ident, $kind:ident, $bits:expr) => {
119         pub fn $name() -> Reg {
120             Reg {
121                 kind: RegKind::$kind,
122                 size: Size::from_bits($bits)
123             }
124         }
125     }
126 }
127
128 impl Reg {
129     reg_ctor!(i8, Integer, 8);
130     reg_ctor!(i16, Integer, 16);
131     reg_ctor!(i32, Integer, 32);
132     reg_ctor!(i64, Integer, 64);
133
134     reg_ctor!(f32, Float, 32);
135     reg_ctor!(f64, Float, 64);
136 }
137
138 impl Reg {
139     pub fn align<C: HasDataLayout>(&self, cx: C) -> Align {
140         let dl = cx.data_layout();
141         match self.kind {
142             RegKind::Integer => {
143                 match self.size.bits() {
144                     1 => dl.i1_align,
145                     2..=8 => dl.i8_align,
146                     9..=16 => dl.i16_align,
147                     17..=32 => dl.i32_align,
148                     33..=64 => dl.i64_align,
149                     65..=128 => dl.i128_align,
150                     _ => panic!("unsupported integer: {:?}", self)
151                 }
152             }
153             RegKind::Float => {
154                 match self.size.bits() {
155                     32 => dl.f32_align,
156                     64 => dl.f64_align,
157                     _ => panic!("unsupported float: {:?}", self)
158                 }
159             }
160             RegKind::Vector => dl.vector_align(self.size)
161         }
162     }
163 }
164
165 /// An argument passed entirely registers with the
166 /// same kind (e.g. HFA / HVA on PPC64 and AArch64).
167 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
168 pub struct Uniform {
169     pub unit: Reg,
170
171     /// The total size of the argument, which can be:
172     /// * equal to `unit.size` (one scalar/vector)
173     /// * a multiple of `unit.size` (an array of scalar/vectors)
174     /// * if `unit.kind` is `Integer`, the last element
175     ///   can be shorter, i.e. `{ i64, i64, i32 }` for
176     ///   64-bit integers with a total size of 20 bytes
177     pub total: Size,
178 }
179
180 impl From<Reg> for Uniform {
181     fn from(unit: Reg) -> Uniform {
182         Uniform {
183             unit,
184             total: unit.size
185         }
186     }
187 }
188
189 impl Uniform {
190     pub fn align<C: HasDataLayout>(&self, cx: C) -> Align {
191         self.unit.align(cx)
192     }
193 }
194
195 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
196 pub struct CastTarget {
197     pub prefix: [Option<RegKind>; 8],
198     pub prefix_chunk: Size,
199     pub rest: Uniform,
200 }
201
202 impl From<Reg> for CastTarget {
203     fn from(unit: Reg) -> CastTarget {
204         CastTarget::from(Uniform::from(unit))
205     }
206 }
207
208 impl From<Uniform> for CastTarget {
209     fn from(uniform: Uniform) -> CastTarget {
210         CastTarget {
211             prefix: [None; 8],
212             prefix_chunk: Size::ZERO,
213             rest: uniform
214         }
215     }
216 }
217
218 impl CastTarget {
219     pub fn pair(a: Reg, b: Reg) -> CastTarget {
220         CastTarget {
221             prefix: [Some(a.kind), None, None, None, None, None, None, None],
222             prefix_chunk: a.size,
223             rest: Uniform::from(b)
224         }
225     }
226
227     pub fn size<C: HasDataLayout>(&self, cx: C) -> Size {
228         (self.prefix_chunk * self.prefix.iter().filter(|x| x.is_some()).count() as u64)
229              .abi_align(self.rest.align(cx)) + self.rest.total
230     }
231
232     pub fn align<C: HasDataLayout>(&self, cx: C) -> Align {
233         self.prefix.iter()
234             .filter_map(|x| x.map(|kind| Reg { kind, size: self.prefix_chunk }.align(cx)))
235             .fold(cx.data_layout().aggregate_align.max(self.rest.align(cx)),
236                 |acc, align| acc.max(align))
237     }
238 }
239
240 impl<'a, Ty> TyLayout<'a, Ty> {
241     fn is_aggregate(&self) -> bool {
242         match self.abi {
243             Abi::Uninhabited |
244             Abi::Scalar(_) |
245             Abi::Vector { .. } => false,
246             Abi::ScalarPair(..) |
247             Abi::Aggregate { .. } => true
248         }
249     }
250
251     fn homogeneous_aggregate<C>(&self, cx: C) -> Option<Reg>
252         where Ty: TyLayoutMethods<'a, C> + Copy, C: LayoutOf<Ty = Ty, TyLayout = Self> + Copy
253     {
254         match self.abi {
255             Abi::Uninhabited => None,
256
257             // The primitive for this algorithm.
258             Abi::Scalar(ref scalar) => {
259                 let kind = match scalar.value {
260                     abi::Int(..) |
261                     abi::Pointer => RegKind::Integer,
262                     abi::Float(_) => RegKind::Float,
263                 };
264                 Some(Reg {
265                     kind,
266                     size: self.size
267                 })
268             }
269
270             Abi::Vector { .. } => {
271                 Some(Reg {
272                     kind: RegKind::Vector,
273                     size: self.size
274                 })
275             }
276
277             Abi::ScalarPair(..) |
278             Abi::Aggregate { .. } => {
279                 let mut total = Size::ZERO;
280                 let mut result = None;
281
282                 let is_union = match self.fields {
283                     FieldPlacement::Array { count, .. } => {
284                         if count > 0 {
285                             return self.field(cx, 0).homogeneous_aggregate(cx);
286                         } else {
287                             return None;
288                         }
289                     }
290                     FieldPlacement::Union(_) => true,
291                     FieldPlacement::Arbitrary { .. } => false
292                 };
293
294                 for i in 0..self.fields.count() {
295                     if !is_union && total != self.fields.offset(i) {
296                         return None;
297                     }
298
299                     let field = self.field(cx, i);
300                     match (result, field.homogeneous_aggregate(cx)) {
301                         // The field itself must be a homogeneous aggregate.
302                         (_, None) => return None,
303                         // If this is the first field, record the unit.
304                         (None, Some(unit)) => {
305                             result = Some(unit);
306                         }
307                         // For all following fields, the unit must be the same.
308                         (Some(prev_unit), Some(unit)) => {
309                             if prev_unit != unit {
310                                 return None;
311                             }
312                         }
313                     }
314
315                     // Keep track of the offset (without padding).
316                     let size = field.size;
317                     if is_union {
318                         total = total.max(size);
319                     } else {
320                         total += size;
321                     }
322                 }
323
324                 // There needs to be no padding.
325                 if total != self.size {
326                     None
327                 } else {
328                     result
329                 }
330             }
331         }
332     }
333 }
334
335 /// Information about how to pass an argument to,
336 /// or return a value from, a function, under some ABI.
337 #[derive(Debug)]
338 pub struct ArgType<'a, Ty> {
339     pub layout: TyLayout<'a, Ty>,
340
341     /// Dummy argument, which is emitted before the real argument.
342     pub pad: Option<Reg>,
343
344     pub mode: PassMode,
345 }
346
347 impl<'a, Ty> ArgType<'a, Ty> {
348     pub fn new(layout: TyLayout<'a, Ty>) -> Self {
349         ArgType {
350             layout,
351             pad: None,
352             mode: PassMode::Direct(ArgAttributes::new()),
353         }
354     }
355
356     pub fn make_indirect(&mut self) {
357         assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new()));
358
359         // Start with fresh attributes for the pointer.
360         let mut attrs = ArgAttributes::new();
361
362         // For non-immediate arguments the callee gets its own copy of
363         // the value on the stack, so there are no aliases. It's also
364         // program-invisible so can't possibly capture
365         attrs.set(ArgAttribute::NoAlias)
366              .set(ArgAttribute::NoCapture)
367              .set(ArgAttribute::NonNull);
368         attrs.pointee_size = self.layout.size;
369         // FIXME(eddyb) We should be doing this, but at least on
370         // i686-pc-windows-msvc, it results in wrong stack offsets.
371         // attrs.pointee_align = Some(self.layout.align);
372
373         let extra_attrs = if self.layout.is_unsized() {
374             Some(ArgAttributes::new())
375         } else {
376             None
377         };
378
379         self.mode = PassMode::Indirect(attrs, extra_attrs);
380     }
381
382     pub fn make_indirect_byval(&mut self) {
383         self.make_indirect();
384         match self.mode {
385             PassMode::Indirect(ref mut attrs, _) => {
386                 attrs.set(ArgAttribute::ByVal);
387             }
388             _ => unreachable!()
389         }
390     }
391
392     pub fn extend_integer_width_to(&mut self, bits: u64) {
393         // Only integers have signedness
394         if let Abi::Scalar(ref scalar) = self.layout.abi {
395             if let abi::Int(i, signed) = scalar.value {
396                 if i.size().bits() < bits {
397                     if let PassMode::Direct(ref mut attrs) = self.mode {
398                         attrs.set(if signed {
399                             ArgAttribute::SExt
400                         } else {
401                             ArgAttribute::ZExt
402                         });
403                     }
404                 }
405             }
406         }
407     }
408
409     pub fn cast_to<T: Into<CastTarget>>(&mut self, target: T) {
410         assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new()));
411         self.mode = PassMode::Cast(target.into());
412     }
413
414     pub fn pad_with(&mut self, reg: Reg) {
415         self.pad = Some(reg);
416     }
417
418     pub fn is_indirect(&self) -> bool {
419         match self.mode {
420             PassMode::Indirect(..) => true,
421             _ => false
422         }
423     }
424
425     pub fn is_sized_indirect(&self) -> bool {
426         match self.mode {
427             PassMode::Indirect(_, None) => true,
428             _ => false
429         }
430     }
431
432     pub fn is_unsized_indirect(&self) -> bool {
433         match self.mode {
434             PassMode::Indirect(_, Some(_)) => true,
435             _ => false
436         }
437     }
438
439     pub fn is_ignore(&self) -> bool {
440         self.mode == PassMode::Ignore
441     }
442 }
443
444 #[derive(Copy, Clone, PartialEq, Debug)]
445 pub enum Conv {
446     C,
447
448     ArmAapcs,
449
450     Msp430Intr,
451
452     PtxKernel,
453
454     X86Fastcall,
455     X86Intr,
456     X86Stdcall,
457     X86ThisCall,
458     X86VectorCall,
459
460     X86_64SysV,
461     X86_64Win64,
462
463     AmdGpuKernel,
464 }
465
466 /// Metadata describing how the arguments to a native function
467 /// should be passed in order to respect the native ABI.
468 ///
469 /// I will do my best to describe this structure, but these
470 /// comments are reverse-engineered and may be inaccurate. -NDM
471 #[derive(Debug)]
472 pub struct FnType<'a, Ty> {
473     /// The LLVM types of each argument.
474     pub args: Vec<ArgType<'a, Ty>>,
475
476     /// LLVM return type.
477     pub ret: ArgType<'a, Ty>,
478
479     pub variadic: bool,
480
481     pub conv: Conv,
482 }
483
484 impl<'a, Ty> FnType<'a, Ty> {
485     pub fn adjust_for_cabi<C>(&mut self, cx: C, abi: ::spec::abi::Abi) -> Result<(), String>
486         where Ty: TyLayoutMethods<'a, C> + Copy,
487               C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout + HasTargetSpec
488     {
489         match &cx.target_spec().arch[..] {
490             "x86" => {
491                 let flavor = if abi == ::spec::abi::Abi::Fastcall {
492                     x86::Flavor::Fastcall
493                 } else {
494                     x86::Flavor::General
495                 };
496                 x86::compute_abi_info(cx, self, flavor);
497             },
498             "x86_64" => if abi == ::spec::abi::Abi::SysV64 {
499                 x86_64::compute_abi_info(cx, self);
500             } else if abi == ::spec::abi::Abi::Win64 || cx.target_spec().options.is_like_windows {
501                 x86_win64::compute_abi_info(self);
502             } else {
503                 x86_64::compute_abi_info(cx, self);
504             },
505             "aarch64" => aarch64::compute_abi_info(cx, self),
506             "arm" => arm::compute_abi_info(cx, self),
507             "mips" => mips::compute_abi_info(cx, self),
508             "mips64" => mips64::compute_abi_info(cx, self),
509             "powerpc" => powerpc::compute_abi_info(cx, self),
510             "powerpc64" => powerpc64::compute_abi_info(cx, self),
511             "s390x" => s390x::compute_abi_info(cx, self),
512             "asmjs" => asmjs::compute_abi_info(cx, self),
513             "wasm32" => {
514                 if cx.target_spec().llvm_target.contains("emscripten") {
515                     asmjs::compute_abi_info(cx, self)
516                 } else {
517                     wasm32::compute_abi_info(self)
518                 }
519             }
520             "msp430" => msp430::compute_abi_info(self),
521             "sparc" => sparc::compute_abi_info(cx, self),
522             "sparc64" => sparc64::compute_abi_info(cx, self),
523             "nvptx" => nvptx::compute_abi_info(self),
524             "nvptx64" => nvptx64::compute_abi_info(self),
525             "hexagon" => hexagon::compute_abi_info(self),
526             "riscv32" => riscv::compute_abi_info(self, 32),
527             "riscv64" => riscv::compute_abi_info(self, 64),
528             a => return Err(format!("unrecognized arch \"{}\" in target specification", a))
529         }
530
531         if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode {
532             attrs.set(ArgAttribute::StructRet);
533         }
534
535         Ok(())
536     }
537 }