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