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