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