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