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