]> git.lizzy.rs Git - rust.git/blob - src/librustc_target/abi/mod.rs
50ce0ad6915da3c9916c1c99ad1d754932590048
[rust.git] / src / librustc_target / abi / 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 pub use self::Integer::*;
12 pub use self::Primitive::*;
13
14 use spec::Target;
15
16 use std::fmt;
17 use std::ops::{Add, Deref, Sub, Mul, AddAssign, Range, RangeInclusive};
18
19 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
20
21 pub mod call;
22
23 /// Parsed [Data layout](http://llvm.org/docs/LangRef.html#data-layout)
24 /// for a target, which contains everything needed to compute layouts.
25 pub struct TargetDataLayout {
26     pub endian: Endian,
27     pub i1_align: AbiAndPrefAlign,
28     pub i8_align: AbiAndPrefAlign,
29     pub i16_align: AbiAndPrefAlign,
30     pub i32_align: AbiAndPrefAlign,
31     pub i64_align: AbiAndPrefAlign,
32     pub i128_align: AbiAndPrefAlign,
33     pub f32_align: AbiAndPrefAlign,
34     pub f64_align: AbiAndPrefAlign,
35     pub pointer_size: Size,
36     pub pointer_align: AbiAndPrefAlign,
37     pub aggregate_align: AbiAndPrefAlign,
38
39     /// Alignments for vector types.
40     pub vector_align: Vec<(Size, AbiAndPrefAlign)>,
41
42     pub instruction_address_space: u32,
43 }
44
45 impl Default for TargetDataLayout {
46     /// Creates an instance of `TargetDataLayout`.
47     fn default() -> TargetDataLayout {
48         let align = |bits| Align::from_bits(bits).unwrap();
49         TargetDataLayout {
50             endian: Endian::Big,
51             i1_align: AbiAndPrefAlign::new(align(8)),
52             i8_align: AbiAndPrefAlign::new(align(8)),
53             i16_align: AbiAndPrefAlign::new(align(16)),
54             i32_align: AbiAndPrefAlign::new(align(32)),
55             i64_align: AbiAndPrefAlign { abi: align(32), pref: align(64) },
56             i128_align: AbiAndPrefAlign { abi: align(32), pref: align(64) },
57             f32_align: AbiAndPrefAlign::new(align(32)),
58             f64_align: AbiAndPrefAlign::new(align(64)),
59             pointer_size: Size::from_bits(64),
60             pointer_align: AbiAndPrefAlign::new(align(64)),
61             aggregate_align: AbiAndPrefAlign { abi: align(0), pref: align(64) },
62             vector_align: vec![
63                 (Size::from_bits(64), AbiAndPrefAlign::new(align(64))),
64                 (Size::from_bits(128), AbiAndPrefAlign::new(align(128))),
65             ],
66             instruction_address_space: 0,
67         }
68     }
69 }
70
71 impl TargetDataLayout {
72     pub fn parse(target: &Target) -> Result<TargetDataLayout, String> {
73         // Parse an address space index from a string.
74         let parse_address_space = |s: &str, cause: &str| {
75             s.parse::<u32>().map_err(|err| {
76                 format!("invalid address space `{}` for `{}` in \"data-layout\": {}",
77                         s, cause, err)
78             })
79         };
80
81         // Parse a bit count from a string.
82         let parse_bits = |s: &str, kind: &str, cause: &str| {
83             s.parse::<u64>().map_err(|err| {
84                 format!("invalid {} `{}` for `{}` in \"data-layout\": {}",
85                         kind, s, cause, err)
86             })
87         };
88
89         // Parse a size string.
90         let size = |s: &str, cause: &str| {
91             parse_bits(s, "size", cause).map(Size::from_bits)
92         };
93
94         // Parse an alignment string.
95         let align = |s: &[&str], cause: &str| {
96             if s.is_empty() {
97                 return Err(format!("missing alignment for `{}` in \"data-layout\"", cause));
98             }
99             let align_from_bits = |bits| {
100                 Align::from_bits(bits).map_err(|err| {
101                     format!("invalid alignment for `{}` in \"data-layout\": {}",
102                             cause, err)
103                 })
104             };
105             let abi = parse_bits(s[0], "alignment", cause)?;
106             let pref = s.get(1).map_or(Ok(abi), |pref| parse_bits(pref, "alignment", cause))?;
107             Ok(AbiAndPrefAlign {
108                 abi: align_from_bits(abi)?,
109                 pref: align_from_bits(pref)?,
110             })
111         };
112
113         let mut dl = TargetDataLayout::default();
114         let mut i128_align_src = 64;
115         for spec in target.data_layout.split('-') {
116             match spec.split(':').collect::<Vec<_>>()[..] {
117                 ["e"] => dl.endian = Endian::Little,
118                 ["E"] => dl.endian = Endian::Big,
119                 [p] if p.starts_with("P") => {
120                     dl.instruction_address_space = parse_address_space(&p[1..], "P")?
121                 }
122                 ["a", ref a..] => dl.aggregate_align = align(a, "a")?,
123                 ["f32", ref a..] => dl.f32_align = align(a, "f32")?,
124                 ["f64", ref a..] => dl.f64_align = align(a, "f64")?,
125                 [p @ "p", s, ref a..] | [p @ "p0", s, ref a..] => {
126                     dl.pointer_size = size(s, p)?;
127                     dl.pointer_align = align(a, p)?;
128                 }
129                 [s, ref a..] if s.starts_with("i") => {
130                     let bits = match s[1..].parse::<u64>() {
131                         Ok(bits) => bits,
132                         Err(_) => {
133                             size(&s[1..], "i")?; // For the user error.
134                             continue;
135                         }
136                     };
137                     let a = align(a, s)?;
138                     match bits {
139                         1 => dl.i1_align = a,
140                         8 => dl.i8_align = a,
141                         16 => dl.i16_align = a,
142                         32 => dl.i32_align = a,
143                         64 => dl.i64_align = a,
144                         _ => {}
145                     }
146                     if bits >= i128_align_src && bits <= 128 {
147                         // Default alignment for i128 is decided by taking the alignment of
148                         // largest-sized i{64...128}.
149                         i128_align_src = bits;
150                         dl.i128_align = a;
151                     }
152                 }
153                 [s, ref a..] if s.starts_with("v") => {
154                     let v_size = size(&s[1..], "v")?;
155                     let a = align(a, s)?;
156                     if let Some(v) = dl.vector_align.iter_mut().find(|v| v.0 == v_size) {
157                         v.1 = a;
158                         continue;
159                     }
160                     // No existing entry, add a new one.
161                     dl.vector_align.push((v_size, a));
162                 }
163                 _ => {} // Ignore everything else.
164             }
165         }
166
167         // Perform consistency checks against the Target information.
168         let endian_str = match dl.endian {
169             Endian::Little => "little",
170             Endian::Big => "big"
171         };
172         if endian_str != target.target_endian {
173             return Err(format!("inconsistent target specification: \"data-layout\" claims \
174                                 architecture is {}-endian, while \"target-endian\" is `{}`",
175                                endian_str, target.target_endian));
176         }
177
178         if dl.pointer_size.bits().to_string() != target.target_pointer_width {
179             return Err(format!("inconsistent target specification: \"data-layout\" claims \
180                                 pointers are {}-bit, while \"target-pointer-width\" is `{}`",
181                                dl.pointer_size.bits(), target.target_pointer_width));
182         }
183
184         Ok(dl)
185     }
186
187     /// Return exclusive upper bound on object size.
188     ///
189     /// The theoretical maximum object size is defined as the maximum positive `isize` value.
190     /// This ensures that the `offset` semantics remain well-defined by allowing it to correctly
191     /// index every address within an object along with one byte past the end, along with allowing
192     /// `isize` to store the difference between any two pointers into an object.
193     ///
194     /// The upper bound on 64-bit currently needs to be lower because LLVM uses a 64-bit integer
195     /// to represent object size in bits. It would need to be 1 << 61 to account for this, but is
196     /// currently conservatively bounded to 1 << 47 as that is enough to cover the current usable
197     /// address space on 64-bit ARMv8 and x86_64.
198     pub fn obj_size_bound(&self) -> u64 {
199         match self.pointer_size.bits() {
200             16 => 1 << 15,
201             32 => 1 << 31,
202             64 => 1 << 47,
203             bits => panic!("obj_size_bound: unknown pointer bit size {}", bits)
204         }
205     }
206
207     pub fn ptr_sized_integer(&self) -> Integer {
208         match self.pointer_size.bits() {
209             16 => I16,
210             32 => I32,
211             64 => I64,
212             bits => panic!("ptr_sized_integer: unknown pointer bit size {}", bits)
213         }
214     }
215
216     pub fn vector_align(&self, vec_size: Size) -> AbiAndPrefAlign {
217         for &(size, align) in &self.vector_align {
218             if size == vec_size {
219                 return align;
220             }
221         }
222         // Default to natural alignment, which is what LLVM does.
223         // That is, use the size, rounded up to a power of 2.
224         AbiAndPrefAlign::new(Align::from_bytes(vec_size.bytes().next_power_of_two()).unwrap())
225     }
226 }
227
228 pub trait HasDataLayout {
229     fn data_layout(&self) -> &TargetDataLayout;
230 }
231
232 impl HasDataLayout for TargetDataLayout {
233     fn data_layout(&self) -> &TargetDataLayout {
234         self
235     }
236 }
237
238 /// Endianness of the target, which must match cfg(target-endian).
239 #[derive(Copy, Clone, PartialEq)]
240 pub enum Endian {
241     Little,
242     Big
243 }
244
245 /// Size of a type in bytes.
246 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
247 pub struct Size {
248     raw: u64
249 }
250
251 impl Size {
252     pub const ZERO: Size = Self::from_bytes(0);
253
254     #[inline]
255     pub fn from_bits(bits: u64) -> Size {
256         // Avoid potential overflow from `bits + 7`.
257         Size::from_bytes(bits / 8 + ((bits % 8) + 7) / 8)
258     }
259
260     #[inline]
261     pub const fn from_bytes(bytes: u64) -> Size {
262         Size {
263             raw: bytes
264         }
265     }
266
267     #[inline]
268     pub fn bytes(self) -> u64 {
269         self.raw
270     }
271
272     #[inline]
273     pub fn bits(self) -> u64 {
274         self.bytes().checked_mul(8).unwrap_or_else(|| {
275             panic!("Size::bits: {} bytes in bits doesn't fit in u64", self.bytes())
276         })
277     }
278
279     #[inline]
280     pub fn align_to(self, align: Align) -> Size {
281         let mask = align.bytes() - 1;
282         Size::from_bytes((self.bytes() + mask) & !mask)
283     }
284
285     #[inline]
286     pub fn is_aligned(self, align: Align) -> bool {
287         let mask = align.bytes() - 1;
288         self.bytes() & mask == 0
289     }
290
291     #[inline]
292     pub fn checked_add<C: HasDataLayout>(self, offset: Size, cx: &C) -> Option<Size> {
293         let dl = cx.data_layout();
294
295         let bytes = self.bytes().checked_add(offset.bytes())?;
296
297         if bytes < dl.obj_size_bound() {
298             Some(Size::from_bytes(bytes))
299         } else {
300             None
301         }
302     }
303
304     #[inline]
305     pub fn checked_mul<C: HasDataLayout>(self, count: u64, cx: &C) -> Option<Size> {
306         let dl = cx.data_layout();
307
308         let bytes = self.bytes().checked_mul(count)?;
309         if bytes < dl.obj_size_bound() {
310             Some(Size::from_bytes(bytes))
311         } else {
312             None
313         }
314     }
315 }
316
317 // Panicking addition, subtraction and multiplication for convenience.
318 // Avoid during layout computation, return `LayoutError` instead.
319
320 impl Add for Size {
321     type Output = Size;
322     #[inline]
323     fn add(self, other: Size) -> Size {
324         Size::from_bytes(self.bytes().checked_add(other.bytes()).unwrap_or_else(|| {
325             panic!("Size::add: {} + {} doesn't fit in u64", self.bytes(), other.bytes())
326         }))
327     }
328 }
329
330 impl Sub for Size {
331     type Output = Size;
332     #[inline]
333     fn sub(self, other: Size) -> Size {
334         Size::from_bytes(self.bytes().checked_sub(other.bytes()).unwrap_or_else(|| {
335             panic!("Size::sub: {} - {} would result in negative size", self.bytes(), other.bytes())
336         }))
337     }
338 }
339
340 impl Mul<Size> for u64 {
341     type Output = Size;
342     #[inline]
343     fn mul(self, size: Size) -> Size {
344         size * self
345     }
346 }
347
348 impl Mul<u64> for Size {
349     type Output = Size;
350     #[inline]
351     fn mul(self, count: u64) -> Size {
352         match self.bytes().checked_mul(count) {
353             Some(bytes) => Size::from_bytes(bytes),
354             None => {
355                 panic!("Size::mul: {} * {} doesn't fit in u64", self.bytes(), count)
356             }
357         }
358     }
359 }
360
361 impl AddAssign for Size {
362     #[inline]
363     fn add_assign(&mut self, other: Size) {
364         *self = *self + other;
365     }
366 }
367
368 /// Alignment of a type in bytes (always a power of two).
369 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
370 pub struct Align {
371     pow2: u8,
372 }
373
374 impl Align {
375     pub fn from_bits(bits: u64) -> Result<Align, String> {
376         Align::from_bytes(Size::from_bits(bits).bytes())
377     }
378
379     pub fn from_bytes(align: u64) -> Result<Align, String> {
380         // Treat an alignment of 0 bytes like 1-byte alignment.
381         if align == 0 {
382             return Ok(Align { pow2: 0 });
383         }
384
385         let mut bytes = align;
386         let mut pow2: u8 = 0;
387         while (bytes & 1) == 0 {
388             pow2 += 1;
389             bytes >>= 1;
390         }
391         if bytes != 1 {
392             return Err(format!("`{}` is not a power of 2", align));
393         }
394         if pow2 > 29 {
395             return Err(format!("`{}` is too large", align));
396         }
397
398         Ok(Align { pow2 })
399     }
400
401     pub fn bytes(self) -> u64 {
402         1 << self.pow2
403     }
404
405     pub fn bits(self) -> u64 {
406         self.bytes() * 8
407     }
408
409     /// Compute the best alignment possible for the given offset
410     /// (the largest power of two that the offset is a multiple of).
411     ///
412     /// NB: for an offset of `0`, this happens to return `2^64`.
413     pub fn max_for_offset(offset: Size) -> Align {
414         Align {
415             pow2: offset.bytes().trailing_zeros() as u8,
416         }
417     }
418
419     /// Lower the alignment, if necessary, such that the given offset
420     /// is aligned to it (the offset is a multiple of the alignment).
421     pub fn restrict_for_offset(self, offset: Size) -> Align {
422         self.min(Align::max_for_offset(offset))
423     }
424 }
425
426 /// A pair of aligments, ABI-mandated and preferred.
427 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
428 pub struct AbiAndPrefAlign {
429     pub abi: Align,
430     pub pref: Align,
431 }
432
433 impl AbiAndPrefAlign {
434     pub fn new(align: Align) -> AbiAndPrefAlign {
435         AbiAndPrefAlign {
436             abi: align,
437             pref: align,
438         }
439     }
440
441     pub fn min(self, other: AbiAndPrefAlign) -> AbiAndPrefAlign {
442         AbiAndPrefAlign {
443             abi: self.abi.min(other.abi),
444             pref: self.pref.min(other.pref),
445         }
446     }
447
448     pub fn max(self, other: AbiAndPrefAlign) -> AbiAndPrefAlign {
449         AbiAndPrefAlign {
450             abi: self.abi.max(other.abi),
451             pref: self.pref.max(other.pref),
452         }
453     }
454 }
455
456 /// Integers, also used for enum discriminants.
457 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
458 pub enum Integer {
459     I8,
460     I16,
461     I32,
462     I64,
463     I128,
464 }
465
466 impl Integer {
467     pub fn size(self) -> Size {
468         match self {
469             I8 => Size::from_bytes(1),
470             I16 => Size::from_bytes(2),
471             I32 => Size::from_bytes(4),
472             I64  => Size::from_bytes(8),
473             I128  => Size::from_bytes(16),
474         }
475     }
476
477     pub fn align<C: HasDataLayout>(self, cx: &C) -> AbiAndPrefAlign {
478         let dl = cx.data_layout();
479
480         match self {
481             I8 => dl.i8_align,
482             I16 => dl.i16_align,
483             I32 => dl.i32_align,
484             I64 => dl.i64_align,
485             I128 => dl.i128_align,
486         }
487     }
488
489     /// Find the smallest Integer type which can represent the signed value.
490     pub fn fit_signed(x: i128) -> Integer {
491         match x {
492             -0x0000_0000_0000_0080..=0x0000_0000_0000_007f => I8,
493             -0x0000_0000_0000_8000..=0x0000_0000_0000_7fff => I16,
494             -0x0000_0000_8000_0000..=0x0000_0000_7fff_ffff => I32,
495             -0x8000_0000_0000_0000..=0x7fff_ffff_ffff_ffff => I64,
496             _ => I128
497         }
498     }
499
500     /// Find the smallest Integer type which can represent the unsigned value.
501     pub fn fit_unsigned(x: u128) -> Integer {
502         match x {
503             0..=0x0000_0000_0000_00ff => I8,
504             0..=0x0000_0000_0000_ffff => I16,
505             0..=0x0000_0000_ffff_ffff => I32,
506             0..=0xffff_ffff_ffff_ffff => I64,
507             _ => I128,
508         }
509     }
510
511     /// Find the smallest integer with the given alignment.
512     pub fn for_align<C: HasDataLayout>(cx: &C, wanted: Align) -> Option<Integer> {
513         let dl = cx.data_layout();
514
515         for &candidate in &[I8, I16, I32, I64, I128] {
516             if wanted == candidate.align(dl).abi && wanted.bytes() == candidate.size().bytes() {
517                 return Some(candidate);
518             }
519         }
520         None
521     }
522
523     /// Find the largest integer with the given alignment or less.
524     pub fn approximate_align<C: HasDataLayout>(cx: &C, wanted: Align) -> Integer {
525         let dl = cx.data_layout();
526
527         // FIXME(eddyb) maybe include I128 in the future, when it works everywhere.
528         for &candidate in &[I64, I32, I16] {
529             if wanted >= candidate.align(dl).abi && wanted.bytes() >= candidate.size().bytes() {
530                 return candidate;
531             }
532         }
533         I8
534     }
535 }
536
537
538 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy,
539          PartialOrd, Ord)]
540 pub enum FloatTy {
541     F32,
542     F64,
543 }
544
545 impl fmt::Debug for FloatTy {
546     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
547         fmt::Display::fmt(self, f)
548     }
549 }
550
551 impl fmt::Display for FloatTy {
552     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
553         write!(f, "{}", self.ty_to_string())
554     }
555 }
556
557 impl FloatTy {
558     pub fn ty_to_string(self) -> &'static str {
559         match self {
560             FloatTy::F32 => "f32",
561             FloatTy::F64 => "f64",
562         }
563     }
564
565     pub fn bit_width(self) -> usize {
566         match self {
567             FloatTy::F32 => 32,
568             FloatTy::F64 => 64,
569         }
570     }
571 }
572
573 /// Fundamental unit of memory access and layout.
574 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
575 pub enum Primitive {
576     /// The `bool` is the signedness of the `Integer` type.
577     ///
578     /// One would think we would not care about such details this low down,
579     /// but some ABIs are described in terms of C types and ISAs where the
580     /// integer arithmetic is done on {sign,zero}-extended registers, e.g.
581     /// a negative integer passed by zero-extension will appear positive in
582     /// the callee, and most operations on it will produce the wrong values.
583     Int(Integer, bool),
584     Float(FloatTy),
585     Pointer
586 }
587
588 impl<'a, 'tcx> Primitive {
589     pub fn size<C: HasDataLayout>(self, cx: &C) -> Size {
590         let dl = cx.data_layout();
591
592         match self {
593             Int(i, _) => i.size(),
594             Float(FloatTy::F32) => Size::from_bits(32),
595             Float(FloatTy::F64) => Size::from_bits(64),
596             Pointer => dl.pointer_size
597         }
598     }
599
600     pub fn align<C: HasDataLayout>(self, cx: &C) -> AbiAndPrefAlign {
601         let dl = cx.data_layout();
602
603         match self {
604             Int(i, _) => i.align(dl),
605             Float(FloatTy::F32) => dl.f32_align,
606             Float(FloatTy::F64) => dl.f64_align,
607             Pointer => dl.pointer_align
608         }
609     }
610
611     pub fn is_float(self) -> bool {
612         match self {
613             Float(_) => true,
614             _ => false
615         }
616     }
617
618     pub fn is_int(self) -> bool {
619         match self {
620             Int(..) => true,
621             _ => false,
622         }
623     }
624 }
625
626 /// Information about one scalar component of a Rust type.
627 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
628 pub struct Scalar {
629     pub value: Primitive,
630
631     /// Inclusive wrap-around range of valid values, that is, if
632     /// start > end, it represents `start..=max_value()`,
633     /// followed by `0..=end`.
634     ///
635     /// That is, for an i8 primitive, a range of `254..=2` means following
636     /// sequence:
637     ///
638     ///    254 (-2), 255 (-1), 0, 1, 2
639     ///
640     /// This is intended specifically to mirror LLVM’s `!range` metadata,
641     /// semantics.
642     // FIXME(eddyb) always use the shortest range, e.g. by finding
643     // the largest space between two consecutive valid values and
644     // taking everything else as the (shortest) valid range.
645     pub valid_range: RangeInclusive<u128>,
646 }
647
648 impl Scalar {
649     pub fn is_bool(&self) -> bool {
650         if let Int(I8, _) = self.value {
651             self.valid_range == (0..=1)
652         } else {
653             false
654         }
655     }
656
657     /// Returns the valid range as a `x..y` range.
658     ///
659     /// If `x` and `y` are equal, the range is full, not empty.
660     pub fn valid_range_exclusive<C: HasDataLayout>(&self, cx: &C) -> Range<u128> {
661         // For a (max) value of -1, max will be `-1 as usize`, which overflows.
662         // However, that is fine here (it would still represent the full range),
663         // i.e., if the range is everything.
664         let bits = self.value.size(cx).bits();
665         assert!(bits <= 128);
666         let mask = !0u128 >> (128 - bits);
667         let start = *self.valid_range.start();
668         let end = *self.valid_range.end();
669         assert_eq!(start, start & mask);
670         assert_eq!(end, end & mask);
671         start..(end.wrapping_add(1) & mask)
672     }
673 }
674
675 /// Describes how the fields of a type are located in memory.
676 #[derive(PartialEq, Eq, Hash, Debug)]
677 pub enum FieldPlacement {
678     /// All fields start at no offset. The `usize` is the field count.
679     ///
680     /// In the case of primitives the number of fields is `0`.
681     Union(usize),
682
683     /// Array/vector-like placement, with all fields of identical types.
684     Array {
685         stride: Size,
686         count: u64
687     },
688
689     /// Struct-like placement, with precomputed offsets.
690     ///
691     /// Fields are guaranteed to not overlap, but note that gaps
692     /// before, between and after all the fields are NOT always
693     /// padding, and as such their contents may not be discarded.
694     /// For example, enum variants leave a gap at the start,
695     /// where the discriminant field in the enum layout goes.
696     Arbitrary {
697         /// Offsets for the first byte of each field,
698         /// ordered to match the source definition order.
699         /// This vector does not go in increasing order.
700         // FIXME(eddyb) use small vector optimization for the common case.
701         offsets: Vec<Size>,
702
703         /// Maps source order field indices to memory order indices,
704         /// depending how fields were permuted.
705         // FIXME(camlorn) also consider small vector  optimization here.
706         memory_index: Vec<u32>
707     }
708 }
709
710 impl FieldPlacement {
711     pub fn count(&self) -> usize {
712         match *self {
713             FieldPlacement::Union(count) => count,
714             FieldPlacement::Array { count, .. } => {
715                 let usize_count = count as usize;
716                 assert_eq!(usize_count as u64, count);
717                 usize_count
718             }
719             FieldPlacement::Arbitrary { ref offsets, .. } => offsets.len()
720         }
721     }
722
723     pub fn offset(&self, i: usize) -> Size {
724         match *self {
725             FieldPlacement::Union(_) => Size::ZERO,
726             FieldPlacement::Array { stride, count } => {
727                 let i = i as u64;
728                 assert!(i < count);
729                 stride * i
730             }
731             FieldPlacement::Arbitrary { ref offsets, .. } => offsets[i]
732         }
733     }
734
735     pub fn memory_index(&self, i: usize) -> usize {
736         match *self {
737             FieldPlacement::Union(_) |
738             FieldPlacement::Array { .. } => i,
739             FieldPlacement::Arbitrary { ref memory_index, .. } => {
740                 let r = memory_index[i];
741                 assert_eq!(r as usize as u32, r);
742                 r as usize
743             }
744         }
745     }
746
747     /// Get source indices of the fields by increasing offsets.
748     #[inline]
749     pub fn index_by_increasing_offset<'a>(&'a self) -> impl Iterator<Item=usize>+'a {
750         let mut inverse_small = [0u8; 64];
751         let mut inverse_big = vec![];
752         let use_small = self.count() <= inverse_small.len();
753
754         // We have to write this logic twice in order to keep the array small.
755         if let FieldPlacement::Arbitrary { ref memory_index, .. } = *self {
756             if use_small {
757                 for i in 0..self.count() {
758                     inverse_small[memory_index[i] as usize] = i as u8;
759                 }
760             } else {
761                 inverse_big = vec![0; self.count()];
762                 for i in 0..self.count() {
763                     inverse_big[memory_index[i] as usize] = i as u32;
764                 }
765             }
766         }
767
768         (0..self.count()).map(move |i| {
769             match *self {
770                 FieldPlacement::Union(_) |
771                 FieldPlacement::Array { .. } => i,
772                 FieldPlacement::Arbitrary { .. } => {
773                     if use_small { inverse_small[i] as usize }
774                     else { inverse_big[i] as usize }
775                 }
776             }
777         })
778     }
779 }
780
781 /// Describes how values of the type are passed by target ABIs,
782 /// in terms of categories of C types there are ABI rules for.
783 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
784 pub enum Abi {
785     Uninhabited,
786     Scalar(Scalar),
787     ScalarPair(Scalar, Scalar),
788     Vector {
789         element: Scalar,
790         count: u64
791     },
792     Aggregate {
793         /// If true, the size is exact, otherwise it's only a lower bound.
794         sized: bool,
795     }
796 }
797
798 impl Abi {
799     /// Returns true if the layout corresponds to an unsized type.
800     pub fn is_unsized(&self) -> bool {
801         match *self {
802             Abi::Uninhabited |
803             Abi::Scalar(_) |
804             Abi::ScalarPair(..) |
805             Abi::Vector { .. } => false,
806             Abi::Aggregate { sized } => !sized
807         }
808     }
809
810     /// Returns true if this is a single signed integer scalar
811     pub fn is_signed(&self) -> bool {
812         match *self {
813             Abi::Scalar(ref scal) => match scal.value {
814                 Primitive::Int(_, signed) => signed,
815                 _ => false,
816             },
817             _ => false,
818         }
819     }
820
821     /// Returns true if this is an uninhabited type
822     pub fn is_uninhabited(&self) -> bool {
823         match *self {
824             Abi::Uninhabited => true,
825             _ => false,
826         }
827     }
828 }
829
830 newtype_index! {
831     pub struct VariantIdx { .. }
832 }
833
834 #[derive(PartialEq, Eq, Hash, Debug)]
835 pub enum Variants {
836     /// Single enum variants, structs/tuples, unions, and all non-ADTs.
837     Single {
838         index: VariantIdx,
839     },
840
841     /// General-case enums: for each case there is a struct, and they all have
842     /// all space reserved for the tag, and their first field starts
843     /// at a non-0 offset, after where the tag would go.
844     Tagged {
845         tag: Scalar,
846         variants: IndexVec<VariantIdx, LayoutDetails>,
847     },
848
849     /// Multiple cases distinguished by a niche (values invalid for a type):
850     /// the variant `dataful_variant` contains a niche at an arbitrary
851     /// offset (field 0 of the enum), which for a variant with discriminant
852     /// `d` is set to `(d - niche_variants.start).wrapping_add(niche_start)`.
853     ///
854     /// For example, `Option<(usize, &T)>`  is represented such that
855     /// `None` has a null pointer for the second tuple field, and
856     /// `Some` is the identity function (with a non-null reference).
857     NicheFilling {
858         dataful_variant: VariantIdx,
859         niche_variants: RangeInclusive<VariantIdx>,
860         niche: Scalar,
861         niche_start: u128,
862         variants: IndexVec<VariantIdx, LayoutDetails>,
863     }
864 }
865
866 #[derive(PartialEq, Eq, Hash, Debug)]
867 pub struct LayoutDetails {
868     pub variants: Variants,
869     pub fields: FieldPlacement,
870     pub abi: Abi,
871     pub align: AbiAndPrefAlign,
872     pub size: Size
873 }
874
875 impl LayoutDetails {
876     pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
877         let size = scalar.value.size(cx);
878         let align = scalar.value.align(cx);
879         LayoutDetails {
880             variants: Variants::Single { index: VariantIdx::new(0) },
881             fields: FieldPlacement::Union(0),
882             abi: Abi::Scalar(scalar),
883             size,
884             align,
885         }
886     }
887 }
888
889 /// The details of the layout of a type, alongside the type itself.
890 /// Provides various type traversal APIs (e.g. recursing into fields).
891 ///
892 /// Note that the details are NOT guaranteed to always be identical
893 /// to those obtained from `layout_of(ty)`, as we need to produce
894 /// layouts for which Rust types do not exist, such as enum variants
895 /// or synthetic fields of enums (i.e. discriminants) and fat pointers.
896 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
897 pub struct TyLayout<'a, Ty> {
898     pub ty: Ty,
899     pub details: &'a LayoutDetails
900 }
901
902 impl<'a, Ty> Deref for TyLayout<'a, Ty> {
903     type Target = &'a LayoutDetails;
904     fn deref(&self) -> &&'a LayoutDetails {
905         &self.details
906     }
907 }
908
909 pub trait LayoutOf {
910     type Ty;
911     type TyLayout;
912
913     fn layout_of(&self, ty: Self::Ty) -> Self::TyLayout;
914 }
915
916 pub trait TyLayoutMethods<'a, C: LayoutOf<Ty = Self>>: Sized {
917     fn for_variant(
918         this: TyLayout<'a, Self>,
919         cx: &C,
920         variant_index: VariantIdx,
921     ) -> TyLayout<'a, Self>;
922     fn field(this: TyLayout<'a, Self>, cx: &C, i: usize) -> C::TyLayout;
923 }
924
925 impl<'a, Ty> TyLayout<'a, Ty> {
926     pub fn for_variant<C>(self, cx: &C, variant_index: VariantIdx) -> Self
927     where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> {
928         Ty::for_variant(self, cx, variant_index)
929     }
930     pub fn field<C>(self, cx: &C, i: usize) -> C::TyLayout
931     where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> {
932         Ty::field(self, cx, i)
933     }
934 }
935
936 impl<'a, Ty> TyLayout<'a, Ty> {
937     /// Returns true if the layout corresponds to an unsized type.
938     pub fn is_unsized(&self) -> bool {
939         self.abi.is_unsized()
940     }
941
942     /// Returns true if the type is a ZST and not unsized.
943     pub fn is_zst(&self) -> bool {
944         match self.abi {
945             Abi::Scalar(_) |
946             Abi::ScalarPair(..) |
947             Abi::Vector { .. } => false,
948             Abi::Uninhabited => self.size.bytes() == 0,
949             Abi::Aggregate { sized } => sized && self.size.bytes() == 0
950         }
951     }
952 }