1use std::cmp::Ordering;
5use std::convert::{TryFrom, TryInto};
6use std::fmt::{Debug, Display, Error as FmtError, Formatter, Result as FmtResult};
7use std::num::ParseIntError;
8use std::str::FromStr;
9
10use paste::paste;
11use thiserror::Error;
12
13#[derive(Debug, Error)]
15pub enum AlignError {
16 #[error("supplied shift is too large ({0} > {})", Align::MAX_SHIFT)]
18 ShiftTooBig(u8),
19 #[error("supplied value is not a power of two: {0}")]
21 NotPowerOfTwo(u64),
22 #[error("supplied value is not a multiple of 8: {0}")]
24 NotByteMultiple(u64),
25}
26
27#[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd)]
31pub struct Align(u8);
32
33impl Debug for Align {
34 fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
35 f.debug_struct("Align")
36 .field("byte_align", &self.byte_align())
37 .finish()
38 }
39}
40
41impl Display for Align {
42 fn fmt(&self, f: &mut Formatter) -> FmtResult {
43 write!(f, "{}", self.byte_align())
44 }
45}
46
47macro_rules! make_const_align {
48 ($align:literal, $shift:literal) => {
49 paste! {
50 pub const [< ALIGN $align >]: Align = Align($shift);
52 }
53 };
54}
55
56impl Align {
57 pub const MAX_SHIFT: u8 = 63;
59
60 make_const_align!(8, 0);
61 make_const_align!(16, 1);
62 make_const_align!(32, 2);
63 make_const_align!(64, 3);
64 make_const_align!(128, 4);
65
66 #[inline(always)]
68 fn is_pow2(value: u64) -> bool {
69 (value > 0) && ((value & (value - 1)) == 0)
70 }
71
72 #[inline(always)]
74 fn log2(value: u64) -> u8 {
75 ((u64::from(u64::BITS) - 1) - u64::from(value.leading_zeros())) as u8
77 }
78
79 pub fn from_shift(shift: u8) -> Result<Align, AlignError> {
82 match shift > Align::MAX_SHIFT {
83 false => Ok(Align(shift)),
84 true => Err(AlignError::ShiftTooBig(shift)),
85 }
86 }
87
88 pub fn from_byte_align(byte_align: u64) -> Result<Align, AlignError> {
91 match Align::is_pow2(byte_align) {
92 true => Align::from_shift(Align::log2(byte_align)),
93 false => Err(AlignError::NotPowerOfTwo(byte_align)),
94 }
95 }
96
97 pub fn from_bit_align(bit_align: u64) -> Result<Align, AlignError> {
100 match bit_align % 8 == 0 {
101 true => Align::from_byte_align(bit_align / 8),
102 false => Err(AlignError::NotByteMultiple(bit_align)),
103 }
104 }
105
106 pub fn shift(&self) -> u8 {
108 self.0
109 }
110
111 pub fn byte_align(&self) -> u64 {
113 1 << self.0
114 }
115
116 pub fn bit_align(&self) -> u64 {
118 self.byte_align() * 8
119 }
120}
121
122#[derive(Debug, Error)]
124pub enum AlignedTypeWidthError {
125 #[error("bit width for type cannot be zero")]
128 Zero,
129 #[error(
131 "bit width for type is too large ({0} > {} bits)",
132 AlignedTypeWidth::MAX
133 )]
134 TooBig(u32),
135}
136
137#[derive(Copy, Clone, Debug, PartialEq)]
139pub struct MaybeAlign(Option<Align>);
140
141impl TryFrom<u8> for MaybeAlign {
142 type Error = AlignError;
143
144 fn try_from(value: u8) -> Result<MaybeAlign, AlignError> {
145 match value {
146 0 => Ok(MaybeAlign(None)),
147 _ => Ok(MaybeAlign(Some(Align::from_shift(value - 1)?))),
148 }
149 }
150}
151
152#[derive(Debug, Copy, Clone, Eq, Ord, PartialEq, PartialOrd)]
155pub struct AlignedTypeWidth(u32);
156
157macro_rules! make_const_width {
158 ($width:literal) => {
159 paste! {
160 pub const [< WIDTH $width >]: AlignedTypeWidth = AlignedTypeWidth($width);
162 }
163 };
164}
165
166impl AlignedTypeWidth {
167 pub const MAX: u32 = (1 << 23) - 1;
169
170 make_const_width!(1);
172 make_const_width!(8);
173 make_const_width!(16);
174 make_const_width!(32);
175 make_const_width!(64);
176 make_const_width!(128);
177}
178
179impl TryFrom<u32> for AlignedTypeWidth {
180 type Error = AlignedTypeWidthError;
181 fn try_from(value: u32) -> Result<Self, Self::Error> {
182 match value > 0 && value <= AlignedTypeWidth::MAX {
183 true => Ok(AlignedTypeWidth(value)),
184 false => Err(AlignedTypeWidthError::TooBig(value)),
185 }
186 }
187}
188
189#[derive(Copy, Clone, Debug, Eq, PartialEq)]
191pub enum AlignedType {
192 Aggregate,
194 Float(AlignedTypeWidth),
196 Integer(AlignedTypeWidth),
198 Vector(AlignedTypeWidth),
200}
201
202impl PartialOrd for AlignedType {
203 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
204 Some(self.cmp(other))
205 }
206}
207
208impl Ord for AlignedType {
209 fn cmp(&self, other: &Self) -> Ordering {
210 match (self, other) {
211 (AlignedType::Aggregate, AlignedType::Aggregate) => Ordering::Equal,
217 (AlignedType::Aggregate, _) => Ordering::Less,
218
219 (AlignedType::Float(_), AlignedType::Aggregate) => Ordering::Greater,
221 (AlignedType::Float(lhs), AlignedType::Float(rhs)) => lhs.cmp(rhs),
222 (AlignedType::Float(_), AlignedType::Integer(_) | AlignedType::Vector(_)) => {
223 Ordering::Less
224 }
225
226 (AlignedType::Integer(_), AlignedType::Aggregate | AlignedType::Float(_)) => {
228 Ordering::Greater
229 }
230 (AlignedType::Integer(lhs), AlignedType::Integer(rhs)) => lhs.cmp(rhs),
231 (AlignedType::Integer(_), AlignedType::Vector(_)) => Ordering::Less,
232
233 (
235 AlignedType::Vector(_),
236 AlignedType::Aggregate | AlignedType::Float(_) | AlignedType::Integer(_),
237 ) => Ordering::Greater,
238 (AlignedType::Vector(lhs), AlignedType::Vector(rhs)) => lhs.cmp(rhs),
239 }
240 }
241}
242
243macro_rules! make_const_aligned {
244 ($name:ident, $width:literal) => {
245 paste! {
246 pub const [< $name:upper $width >]: AlignedType = AlignedType::$name(AlignedTypeWidth::[< WIDTH $width >]);
248 }
249 }
250}
251
252impl AlignedType {
253 make_const_aligned!(Float, 16);
255 make_const_aligned!(Float, 32);
256 make_const_aligned!(Float, 64);
257 make_const_aligned!(Float, 128);
258 make_const_aligned!(Integer, 1);
259 make_const_aligned!(Integer, 8);
260 make_const_aligned!(Integer, 16);
261 make_const_aligned!(Integer, 32);
262 make_const_aligned!(Integer, 64);
263}
264
265#[derive(Debug, Error)]
268pub enum AlignSpecError {
269 #[error("impossible bit width for underlying aligned type")]
271 BadTypeWidth(#[from] AlignedTypeWidthError),
272 #[error("impossible preferred alignment: {0} must be >= {1}")]
274 AlignPref(Align, Align),
275 #[error(
277 "impossible ABI alignment for type: {0} > {}",
278 TypeAlignSpec::MAX_ALIGN
279 )]
280 AbiAlignTooLarge(Align),
281 #[error("error while parsing alignment spec: {0}")]
283 Parse(String),
284 #[error("error while parsing inner alignment in spec")]
287 ParseAlign(#[from] AlignError),
288 #[error("error while parsing integer in alignment spec")]
291 BadInt(#[from] ParseIntError),
292 #[error("invalid address space in spec")]
294 BadAddressSpace(#[from] AddressSpaceError),
295}
296
297#[non_exhaustive]
300#[derive(Debug, Copy, Clone, Eq)]
301pub struct TypeAlignSpec {
302 pub aligned_type: AlignedType,
304 pub abi_alignment: Align,
306 pub preferred_alignment: Align,
311}
312
313impl PartialEq for TypeAlignSpec {
314 fn eq(&self, other: &Self) -> bool {
315 self.aligned_type == other.aligned_type
316 }
317}
318
319impl PartialOrd for TypeAlignSpec {
320 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
321 Some(self.aligned_type.cmp(&other.aligned_type))
322 }
323}
324
325impl Ord for TypeAlignSpec {
326 fn cmp(&self, other: &Self) -> Ordering {
327 self.aligned_type.cmp(&other.aligned_type)
328 }
329}
330
331impl FromStr for TypeAlignSpec {
332 type Err = AlignSpecError;
333
334 fn from_str(value: &str) -> Result<Self, Self::Err> {
335 if value.is_empty() {
336 return Err(AlignSpecError::Parse(
337 "cannot parse type alignment from an empty string".into(),
338 ));
339 }
340
341 #[allow(clippy::unwrap_used)]
343 let id = value.chars().next().unwrap();
344 let body = &value[1..];
345 let parts: Vec<&str> = body.split(':').collect();
346
347 match id {
348 'a' => {
351 let parts = match body.chars().next() {
352 Some(':') => body[1..].split(':').collect::<Vec<&str>>(),
353 Some(o) => {
354 return Err(AlignSpecError::Parse(format!(
355 "unexpected character before aggregate spec: {}",
356 o
357 )))
358 }
359 None => return Err(AlignSpecError::Parse("empty aggregate specifier".into())),
360 };
361
362 if parts.is_empty() {
363 return Err(AlignSpecError::Parse(format!(
364 "wrong number of aggregate alignment parameters: expected at least 1, got {}",
365 parts.len()
366 )));
367 }
368 let abi = parts[0]
369 .parse::<u64>()
370 .map_err(|e| AlignSpecError::Parse(e.to_string()))
371 .and_then(|a| Align::from_bit_align(a).map_err(Into::into))?;
372
373 let pref = parts
374 .get(1)
375 .map(|p| {
376 p.parse::<u64>()
377 .map_err(AlignSpecError::from)
378 .and_then(|a| Align::from_bit_align(a).map_err(Into::into))
379 })
380 .unwrap_or(Ok(abi))?;
381
382 TypeAlignSpec::new(AlignedType::Aggregate, abi, pref)
383 }
384 id => {
387 if parts.len() < 2 {
388 return Err(AlignSpecError::Parse(format!(
389 "wrong number of alignment parameters for spec '{}': expected at least 2, got {}",
390 id,
391 parts.len()
392 )));
393 }
394
395 let bitsize = parts[0]
397 .parse::<u32>()
398 .map_err(|e| AlignSpecError::Parse(e.to_string()))
399 .and_then(|bs| AlignedTypeWidth::try_from(bs).map_err(Into::into))?;
400 let abi = parts[1]
401 .parse::<u64>()
402 .map_err(|e| AlignSpecError::Parse(e.to_string()))
403 .and_then(|a| Align::from_bit_align(a).map_err(Into::into))?;
404 let pref = parts
405 .get(2)
406 .map(|p| {
407 p.parse::<u64>()
408 .map_err(AlignSpecError::from)
409 .and_then(|a| Align::from_bit_align(a).map_err(Into::into))
410 })
411 .unwrap_or(Ok(abi))?;
412
413 match id {
414 'i' => TypeAlignSpec::new(AlignedType::Integer(bitsize), abi, pref),
415 'v' => TypeAlignSpec::new(AlignedType::Vector(bitsize), abi, pref),
416 'f' => TypeAlignSpec::new(AlignedType::Float(bitsize), abi, pref),
417 o => Err(AlignSpecError::Parse(format!(
418 "unknown type for align spec: {}",
419 o
420 ))),
421 }
422 }
423 }
424 }
425}
426
427impl TypeAlignSpec {
428 pub const MAX_TYPE_BIT_WIDTH: u32 = (1 << 23) - 1;
430
431 pub const MAX_ALIGN: Align = Align(15);
437
438 pub fn new(aligned_type: AlignedType, abi: Align, pref: Align) -> Result<Self, AlignSpecError> {
441 if pref < abi {
442 return Err(AlignSpecError::AlignPref(pref, abi));
443 }
444
445 match ((abi <= Self::MAX_ALIGN), (pref <= Self::MAX_ALIGN)) {
446 (true, true) => Ok(Self {
447 aligned_type: aligned_type,
448 abi_alignment: abi,
449 preferred_alignment: pref,
450 }),
451 (_, _) => Err(AlignSpecError::AbiAlignTooLarge(abi)),
456 }
457 }
458}
459
460#[derive(Debug, PartialEq)]
462pub struct TypeAlignSpecs(Vec<TypeAlignSpec>);
463
464impl Default for TypeAlignSpecs {
465 fn default() -> Self {
466 #[allow(clippy::unwrap_used)]
471 Self(vec![
472 TypeAlignSpec::new(AlignedType::Aggregate, Align::ALIGN64, Align::ALIGN64).unwrap(),
473 TypeAlignSpec::new(AlignedType::FLOAT16, Align::ALIGN16, Align::ALIGN16).unwrap(),
474 TypeAlignSpec::new(AlignedType::FLOAT32, Align::ALIGN32, Align::ALIGN32).unwrap(),
475 TypeAlignSpec::new(AlignedType::FLOAT64, Align::ALIGN64, Align::ALIGN64).unwrap(),
476 TypeAlignSpec::new(AlignedType::FLOAT128, Align::ALIGN128, Align::ALIGN128).unwrap(),
477 TypeAlignSpec::new(AlignedType::INTEGER1, Align::ALIGN8, Align::ALIGN8).unwrap(),
478 TypeAlignSpec::new(AlignedType::INTEGER8, Align::ALIGN8, Align::ALIGN8).unwrap(),
479 TypeAlignSpec::new(AlignedType::INTEGER16, Align::ALIGN16, Align::ALIGN16).unwrap(),
480 TypeAlignSpec::new(AlignedType::INTEGER32, Align::ALIGN32, Align::ALIGN32).unwrap(),
481 TypeAlignSpec::new(AlignedType::INTEGER64, Align::ALIGN64, Align::ALIGN64).unwrap(),
482 ])
483 }
484}
485
486impl TypeAlignSpecs {
487 pub fn update(&mut self, spec: TypeAlignSpec) {
490 let pos = self.0.iter().rposition(|&other| other <= spec);
493 match pos {
494 Some(pos) => match self.0[pos] == spec {
498 true => {
499 #[allow(clippy::unwrap_used)]
501 let mut other = self.0.get_mut(pos).unwrap();
502
503 other.abi_alignment = spec.abi_alignment;
504 other.preferred_alignment = spec.preferred_alignment;
505 }
506 false => {
507 self.0.insert(pos + 1, spec);
508 }
509 },
510 None => self.0.insert(0, spec),
512 }
513 }
514}
515
516#[derive(Debug, Error)]
518pub enum AddressSpaceError {
519 #[error("address space identifier is too large ({0} > {})", AddressSpace::MAX)]
521 TooBig(u64),
522}
523
524#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
526pub struct AddressSpace(u32);
527
528impl TryFrom<u32> for AddressSpace {
529 type Error = AddressSpaceError;
530 fn try_from(value: u32) -> Result<Self, Self::Error> {
531 match value <= AddressSpace::MAX {
532 true => Ok(AddressSpace(value)),
533 false => Err(AddressSpaceError::TooBig(value.into())),
534 }
535 }
536}
537
538impl TryFrom<u64> for AddressSpace {
539 type Error = AddressSpaceError;
540 fn try_from(value: u64) -> Result<Self, Self::Error> {
541 match value <= AddressSpace::MAX.into() {
542 true => Ok(AddressSpace(value as u32)),
543 false => Err(AddressSpaceError::TooBig(value)),
544 }
545 }
546}
547
548impl AddressSpace {
549 pub const MAX: u32 = (1 << 23) - 1;
551}
552
553#[non_exhaustive]
556#[derive(Copy, Clone, Debug, Eq, PartialEq)]
557pub struct PointerAlignSpec {
558 pub address_space: AddressSpace,
560 pub abi_alignment: Align,
562 pub preferred_alignment: Align,
567 pub pointer_size: u64,
569 pub index_size: u64,
571}
572
573impl PartialOrd for PointerAlignSpec {
574 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
575 Some(self.address_space.cmp(&other.address_space))
576 }
577}
578
579impl Ord for PointerAlignSpec {
580 fn cmp(&self, other: &Self) -> Ordering {
581 self.address_space.cmp(&other.address_space)
582 }
583}
584
585impl Default for PointerAlignSpec {
588 fn default() -> Self {
589 Self {
590 address_space: AddressSpace::default(),
591 abi_alignment: Align::ALIGN64,
592 preferred_alignment: Align::ALIGN64,
593 pointer_size: 64,
594 index_size: 64,
595 }
596 }
597}
598
599impl FromStr for PointerAlignSpec {
600 type Err = AlignSpecError;
601
602 fn from_str(value: &str) -> Result<Self, Self::Err> {
603 if value.is_empty() {
609 return Err(AlignSpecError::Parse(
610 "cannot parse from an empty string".into(),
611 ));
612 }
613
614 let parts: Vec<&str> = value[1..].split(':').collect();
615
616 if parts.len() < 3 {
619 return Err(AlignSpecError::Parse(format!(
620 "pointer align spec has too few parts ({}, expected at least 4)",
621 parts.len()
622 )));
623 }
624
625 let address_space = match parts[0].is_empty() {
626 true => AddressSpace::default(),
627 false => parts[0].parse::<u32>()?.try_into()?,
628 };
629 let pointer_size = parts[1].parse::<u64>()?;
630 let abi = parts[2]
631 .parse::<u64>()
632 .map_err(|e| AlignSpecError::Parse(e.to_string()))
633 .and_then(|a| Align::from_bit_align(a).map_err(Into::into))?;
634 let pref = parts
635 .get(3)
636 .map(|idx| {
637 idx.parse::<u64>()
638 .map_err(AlignSpecError::from)
639 .and_then(|a| Align::from_bit_align(a).map_err(Into::into))
640 })
641 .unwrap_or(Ok(abi))?;
642 let index_size = parts
643 .get(4)
644 .map(|idx| idx.parse::<u64>())
645 .unwrap_or(Ok(pointer_size))?;
646
647 Ok(Self {
648 address_space: address_space,
649 abi_alignment: abi,
650 preferred_alignment: pref,
651 pointer_size: pointer_size,
652 index_size: index_size,
653 })
654 }
655}
656
657impl PointerAlignSpec {
658 pub fn new(
660 address_space: AddressSpace,
661 abi_alignment: Align,
662 preferred_alignment: Align,
663 pointer_size: u64,
664 index_size: u64,
665 ) -> Result<Self, AlignSpecError> {
666 if preferred_alignment < abi_alignment {
667 return Err(AlignSpecError::AlignPref(
668 preferred_alignment,
669 abi_alignment,
670 ));
671 }
672
673 Ok(Self {
677 address_space,
678 abi_alignment,
679 preferred_alignment,
680 pointer_size,
681 index_size,
682 })
683 }
684}
685
686#[derive(Debug, PartialEq)]
688pub enum FunctionPointerAlign {
689 Independent {
692 abi_alignment: Align,
694 },
695 MultipleOfFunctionAlign {
699 abi_alignment: Align,
701 },
702}
703
704#[derive(Debug, Eq, PartialEq)]
706pub struct PointerAlignSpecs(Vec<PointerAlignSpec>);
707
708impl Default for PointerAlignSpecs {
709 fn default() -> Self {
710 Self(vec![PointerAlignSpec::default()])
711 }
712}
713
714impl PointerAlignSpecs {
715 pub fn update(&mut self, spec: PointerAlignSpec) {
718 let pos = self.0.iter().rposition(|&other| other <= spec);
721 match pos {
722 Some(pos) => match self.0[pos] == spec {
726 true => {
727 #[allow(clippy::unwrap_used)]
729 let mut other = self.0.get_mut(pos).unwrap();
730
731 other.abi_alignment = spec.abi_alignment;
732 other.preferred_alignment = spec.preferred_alignment;
733 }
734 false => {
735 self.0.insert(pos + 1, spec);
736 }
737 },
738 None => self.0.insert(0, spec),
740 }
741 }
742}
743
744#[cfg(test)]
745mod tests {
746 use super::*;
747
748 #[test]
749 fn test_align_constants() {
750 assert_eq!(Align::ALIGN8.byte_align(), 1);
751 assert_eq!(Align::ALIGN16.byte_align(), 2);
752 assert_eq!(Align::ALIGN32.byte_align(), 4);
753 assert_eq!(Align::ALIGN64.byte_align(), 8);
754 assert_eq!(Align::ALIGN128.byte_align(), 16);
755 }
756
757 #[test]
758 fn test_align_is_pow2() {
759 assert!(Align::is_pow2(1));
760 assert!(Align::is_pow2(2));
761 assert!(Align::is_pow2(4));
762 assert!(Align::is_pow2(8));
763 assert!(Align::is_pow2(16));
764 assert!(Align::is_pow2(32));
765 assert!(Align::is_pow2(64));
766
767 assert!(!Align::is_pow2(3));
768 assert!(!Align::is_pow2(6));
769 assert!(!Align::is_pow2(12));
770 assert!(!Align::is_pow2(65));
771 }
772
773 #[test]
774 fn test_align_compares() {
775 assert_eq!(Align::from_shift(1).unwrap(), Align::from_shift(1).unwrap());
776 assert!(Align::from_shift(1).unwrap() < Align::from_shift(2).unwrap());
777 assert!(Align::from_shift(1).unwrap() <= Align::from_shift(2).unwrap());
778 assert!(Align::from_shift(2).unwrap() > Align::from_shift(1).unwrap());
779 assert!(Align::from_shift(2).unwrap() >= Align::from_shift(1).unwrap());
780 }
781
782 #[test]
783 fn test_align_log2() {
784 assert_eq!(Align::log2(1), 0);
785 assert_eq!(Align::log2(2), 1);
786 assert_eq!(Align::log2(4), 2);
787 assert_eq!(Align::log2(8), 3);
788 assert_eq!(Align::log2(16), 4);
789 assert_eq!(Align::log2(32), 5);
790 assert_eq!(Align::log2(64), 6);
791
792 assert_eq!(Align::log2(65), 6);
794 }
795
796 #[test]
797 fn test_align_basic() {
798 for (s, ba) in &[(0, 1), (1, 2), (2, 4), (3, 8), (4, 16), (5, 32), (6, 64)] {
799 let align = Align(*s);
800
801 assert_eq!(align.shift(), *s);
802 assert_eq!(align.byte_align(), *ba);
803 assert_eq!(align.bit_align(), (*ba) * 8);
804 }
805 }
806
807 #[test]
808 fn test_align_from_byte_align() {
809 assert_eq!(Align::from_byte_align(1).unwrap().shift(), 0);
810 assert_eq!(Align::from_byte_align(2).unwrap().shift(), 1);
811 assert_eq!(Align::from_byte_align(4).unwrap().shift(), 2);
812 assert_eq!(Align::from_byte_align(8).unwrap().shift(), 3);
813 assert_eq!(Align::from_byte_align(16).unwrap().shift(), 4);
814 assert_eq!(Align::from_byte_align(32).unwrap().shift(), 5);
815 assert_eq!(Align::from_byte_align(64).unwrap().shift(), 6);
816 assert_eq!(Align::from_byte_align(128).unwrap().shift(), 7);
817
818 assert!(Align::from_byte_align(0).is_err());
819 assert!(Align::from_byte_align(3).is_err());
820 assert!(Align::from_byte_align(7).is_err());
821 assert!(Align::from_byte_align(22).is_err());
822 assert!(Align::from_byte_align(24).is_err());
823 }
824
825 #[test]
826 fn test_align_from_bit_align() {
827 assert_eq!(Align::from_bit_align(8).unwrap().shift(), 0);
828 assert_eq!(Align::from_bit_align(16).unwrap().shift(), 1);
829 assert_eq!(Align::from_bit_align(32).unwrap().shift(), 2);
830 assert_eq!(Align::from_bit_align(64).unwrap().shift(), 3);
831 assert_eq!(Align::from_bit_align(128).unwrap().shift(), 4);
832 assert_eq!(Align::from_bit_align(256).unwrap().shift(), 5);
833 assert_eq!(Align::from_bit_align(512).unwrap().shift(), 6);
834 assert_eq!(Align::from_bit_align(1024).unwrap().shift(), 7);
835
836 assert!(Align::from_bit_align(0).is_err());
837 assert!(Align::from_bit_align(1).is_err());
838 assert!(Align::from_bit_align(7).is_err());
839 assert!(Align::from_bit_align(9).is_err());
840 assert!(Align::from_bit_align(24).is_err());
841 assert!(Align::from_bit_align(33).is_err());
842 }
843
844 #[test]
845 fn test_aligned_type_width() {
846 for i in 1..(1 << 15) {
847 assert!(AlignedTypeWidth::try_from(i).is_ok());
848 }
849
850 assert!(AlignedTypeWidth::try_from(0).is_err());
851 assert!(AlignedTypeWidth::try_from(u32::MAX).is_err());
852 }
853
854 #[test]
855 fn test_aligned_type_ordering() {
856 assert!(
857 AlignedType::Integer(AlignedTypeWidth(1)) == AlignedType::Integer(AlignedTypeWidth(1))
858 );
859 assert!(
860 AlignedType::Vector(AlignedTypeWidth(1)) == AlignedType::Vector(AlignedTypeWidth(1))
861 );
862 assert!(AlignedType::Float(AlignedTypeWidth(1)) == AlignedType::Float(AlignedTypeWidth(1)));
863
864 for i in 2..(1 << 15) {
865 assert!(
866 AlignedType::Integer(AlignedTypeWidth(i))
867 < AlignedType::Vector(AlignedTypeWidth(i))
868 );
869 assert!(
870 AlignedType::Integer(AlignedTypeWidth(i))
871 <= AlignedType::Vector(AlignedTypeWidth(i))
872 );
873
874 assert!(
875 AlignedType::Integer(AlignedTypeWidth(i + 1))
876 < AlignedType::Vector(AlignedTypeWidth(i - 1))
877 );
878 assert!(
879 AlignedType::Integer(AlignedTypeWidth(i + 1))
880 <= AlignedType::Vector(AlignedTypeWidth(i - 1))
881 );
882
883 assert!(
884 AlignedType::Integer(AlignedTypeWidth(i)) > AlignedType::Float(AlignedTypeWidth(i))
885 );
886 assert!(
887 AlignedType::Integer(AlignedTypeWidth(i))
888 >= AlignedType::Float(AlignedTypeWidth(i))
889 );
890
891 assert!(
892 AlignedType::Integer(AlignedTypeWidth(i + 1))
893 > AlignedType::Float(AlignedTypeWidth(i - 1))
894 );
895 assert!(
896 AlignedType::Integer(AlignedTypeWidth(i + 1))
897 >= AlignedType::Float(AlignedTypeWidth(i - 1))
898 );
899
900 assert!(AlignedType::Integer(AlignedTypeWidth(i)) > AlignedType::Aggregate);
901 assert!(AlignedType::Integer(AlignedTypeWidth(i)) >= AlignedType::Aggregate);
902 }
903
904 assert!(AlignedType::Aggregate == AlignedType::Aggregate);
905 }
906
907 #[test]
908 fn test_type_align_spec() {
909 assert!(TypeAlignSpec::new(
911 AlignedType::Integer(AlignedTypeWidth(64)),
912 Align::ALIGN64,
913 Align::ALIGN64
914 )
915 .is_ok());
916 assert!(TypeAlignSpec::new(
917 AlignedType::Integer(AlignedTypeWidth(64)),
918 Align::ALIGN64,
919 Align::ALIGN128
920 )
921 .is_ok());
922 assert!(TypeAlignSpec::new(
923 AlignedType::Float(AlignedTypeWidth(32)),
924 Align::ALIGN32,
925 Align::ALIGN32
926 )
927 .is_ok());
928 assert!(TypeAlignSpec::new(
929 AlignedType::Float(AlignedTypeWidth(32)),
930 Align::ALIGN32,
931 Align::ALIGN64
932 )
933 .is_ok());
934
935 assert_eq!(
937 TypeAlignSpec::new(
938 AlignedType::Integer(AlignedTypeWidth(8)),
939 Align(2),
940 Align(1)
941 )
942 .unwrap_err()
943 .to_string(),
944 "impossible preferred alignment: 2 must be >= 4"
945 );
946
947 assert_eq!(
949 TypeAlignSpec::new(
950 AlignedType::Integer(AlignedTypeWidth(8)),
951 Align(16),
952 Align(16)
953 )
954 .unwrap_err()
955 .to_string(),
956 "impossible ABI alignment for type: 65536 > 32768"
957 );
958 }
959
960 #[test]
961 fn test_type_align_spec_equality() {
962 let spec1 =
964 TypeAlignSpec::new(AlignedType::INTEGER8, Align::ALIGN16, Align::ALIGN16).unwrap();
965
966 let spec2 =
967 TypeAlignSpec::new(AlignedType::INTEGER8, Align::ALIGN16, Align::ALIGN32).unwrap();
968
969 assert_eq!(spec1, spec2);
970 }
971
972 #[test]
973 fn test_type_align_specs_default_sorted() {
974 let specs1 = TypeAlignSpecs::default();
975 let mut specs2 = TypeAlignSpecs::default();
976 specs2.0.sort();
977
978 assert_eq!(specs1, specs2);
979 }
980
981 #[test]
982 fn test_type_align_specs_update() {
983 {
984 let mut specs = TypeAlignSpecs(vec![]);
986 specs.update(
987 TypeAlignSpec::new(AlignedType::INTEGER8, Align::ALIGN16, Align::ALIGN16).unwrap(),
988 );
989
990 assert_eq!(specs.0.len(), 1);
991 }
992
993 {
994 let mut specs = TypeAlignSpecs(vec![]);
996 specs.update(
997 TypeAlignSpec::new(AlignedType::INTEGER8, Align::ALIGN16, Align::ALIGN16).unwrap(),
998 );
999 specs.update(
1000 TypeAlignSpec::new(AlignedType::INTEGER8, Align::ALIGN16, Align::ALIGN32).unwrap(),
1001 );
1002
1003 assert_eq!(specs.0.len(), 1);
1004 }
1005
1006 {
1007 let mut specs = TypeAlignSpecs(vec![]);
1009 specs.update(
1010 TypeAlignSpec::new(AlignedType::Aggregate, Align::ALIGN64, Align::ALIGN64).unwrap(),
1011 );
1012 specs.update(
1013 TypeAlignSpec::new(AlignedType::INTEGER8, Align::ALIGN16, Align::ALIGN16).unwrap(),
1014 );
1015
1016 let copy = {
1017 let mut copy = specs.0.clone();
1018 copy.sort();
1019 TypeAlignSpecs(copy)
1020 };
1021
1022 assert_eq!(specs.0.len(), 2);
1023 assert_eq!(specs, copy);
1024 }
1025
1026 {
1027 let mut specs = TypeAlignSpecs(vec![]);
1029 specs.update(
1030 TypeAlignSpec::new(AlignedType::INTEGER8, Align::ALIGN16, Align::ALIGN16).unwrap(),
1031 );
1032 specs.update(
1033 TypeAlignSpec::new(AlignedType::Aggregate, Align::ALIGN64, Align::ALIGN64).unwrap(),
1034 );
1035
1036 let copy = {
1037 let mut copy = specs.0.clone();
1038 copy.sort();
1039 TypeAlignSpecs(copy)
1040 };
1041
1042 assert_eq!(specs.0.len(), 2);
1043 assert_eq!(specs, copy);
1044 }
1045
1046 {
1047 let mut specs = TypeAlignSpecs(vec![]);
1049 specs.update(
1050 TypeAlignSpec::new(AlignedType::INTEGER8, Align::ALIGN16, Align::ALIGN16).unwrap(),
1051 );
1052 specs.update(
1053 TypeAlignSpec::new(AlignedType::Aggregate, Align::ALIGN64, Align::ALIGN64).unwrap(),
1054 );
1055 specs.update(
1056 TypeAlignSpec::new(AlignedType::FLOAT16, Align::ALIGN16, Align::ALIGN16).unwrap(),
1057 );
1058
1059 let copy = {
1060 let mut copy = specs.0.clone();
1061 copy.sort();
1062 TypeAlignSpecs(copy)
1063 };
1064
1065 assert_eq!(specs.0.len(), 3);
1066 assert_eq!(specs, copy);
1067 }
1068 }
1069
1070 #[test]
1071 fn test_type_align_spec_parse() {
1072 {
1073 let spec = "i64:64:64".parse::<TypeAlignSpec>().unwrap();
1074
1075 assert_eq!(
1076 spec.aligned_type,
1077 AlignedType::Integer(AlignedTypeWidth::WIDTH64)
1078 );
1079 assert_eq!(spec.abi_alignment, Align::ALIGN64);
1080 assert_eq!(spec.preferred_alignment, Align::ALIGN64);
1081 }
1082
1083 {
1084 let spec = "i32:32:64".parse::<TypeAlignSpec>().unwrap();
1085
1086 assert_eq!(
1087 spec.aligned_type,
1088 AlignedType::Integer(AlignedTypeWidth::WIDTH32)
1089 );
1090 assert_eq!(spec.abi_alignment, Align::ALIGN32);
1091 assert_eq!(spec.preferred_alignment, Align::ALIGN64);
1092 }
1093
1094 {
1095 let spec = "a:32:64".parse::<TypeAlignSpec>().unwrap();
1096
1097 assert_eq!(spec.aligned_type, AlignedType::Aggregate);
1098 assert_eq!(spec.abi_alignment, Align::ALIGN32);
1099 assert_eq!(spec.preferred_alignment, Align::ALIGN64);
1100 }
1101
1102 {
1103 let spec = "a:32".parse::<TypeAlignSpec>().unwrap();
1104
1105 assert_eq!(spec.aligned_type, AlignedType::Aggregate);
1106 assert_eq!(spec.abi_alignment, Align::ALIGN32);
1107 assert_eq!(spec.preferred_alignment, Align::ALIGN32);
1108 }
1109 }
1110
1111 #[test]
1112 fn test_pointer_align_spec_parse() {
1113 {
1114 let spec = "p:64:64:64".parse::<PointerAlignSpec>().unwrap();
1115
1116 assert_eq!(spec.address_space, AddressSpace::default());
1117 assert_eq!(spec.pointer_size, 64);
1118 assert_eq!(spec.index_size, 64);
1119 assert_eq!(spec.abi_alignment, Align::ALIGN64);
1120 assert_eq!(spec.preferred_alignment, Align::ALIGN64);
1121 }
1122
1123 {
1124 let spec = "p0:64:64:64".parse::<PointerAlignSpec>().unwrap();
1125
1126 assert_eq!(spec.address_space, AddressSpace::default());
1127 assert_eq!(spec.pointer_size, 64);
1128 assert_eq!(spec.index_size, 64);
1129 assert_eq!(spec.abi_alignment, Align::ALIGN64);
1130 assert_eq!(spec.preferred_alignment, Align::ALIGN64);
1131 }
1132
1133 {
1134 let spec = "p:64:64:64:64".parse::<PointerAlignSpec>().unwrap();
1135
1136 assert_eq!(spec.address_space, AddressSpace::default());
1137 assert_eq!(spec.pointer_size, 64);
1138 assert_eq!(spec.index_size, 64);
1139 assert_eq!(spec.abi_alignment, Align::ALIGN64);
1140 assert_eq!(spec.preferred_alignment, Align::ALIGN64);
1141 }
1142
1143 {
1144 let spec = "p:64:64:64:32".parse::<PointerAlignSpec>().unwrap();
1145
1146 assert_eq!(spec.address_space, AddressSpace::default());
1147 assert_eq!(spec.pointer_size, 64);
1148 assert_eq!(spec.index_size, 32);
1149 assert_eq!(spec.abi_alignment, Align::ALIGN64);
1150 assert_eq!(spec.preferred_alignment, Align::ALIGN64);
1151 }
1152
1153 {
1154 let spec = "p1:64:64:64".parse::<PointerAlignSpec>().unwrap();
1155
1156 assert_eq!(spec.address_space, AddressSpace(1));
1157 assert_eq!(spec.pointer_size, 64);
1158 assert_eq!(spec.index_size, 64);
1159 assert_eq!(spec.abi_alignment, Align::ALIGN64);
1160 assert_eq!(spec.preferred_alignment, Align::ALIGN64);
1161 }
1162
1163 {
1164 let spec = "p1:64:64".parse::<PointerAlignSpec>().unwrap();
1165
1166 assert_eq!(spec.address_space, AddressSpace(1));
1167 assert_eq!(spec.pointer_size, 64);
1168 assert_eq!(spec.index_size, 64);
1169 assert_eq!(spec.abi_alignment, Align::ALIGN64);
1170 assert_eq!(spec.preferred_alignment, Align::ALIGN64);
1171 }
1172 }
1173
1174 #[test]
1175 fn test_address_space() {
1176 assert!(AddressSpace::try_from(0_u32).is_ok());
1177 assert!(AddressSpace::try_from(1_u32).is_ok());
1178 assert!(AddressSpace::try_from(AddressSpace::MAX).is_ok());
1179
1180 assert!(AddressSpace::try_from(AddressSpace::MAX + 1).is_err());
1181 }
1182
1183 #[test]
1184 fn test_address_space_ordering() {
1185 assert!(AddressSpace(0) < AddressSpace(1));
1186 assert!(AddressSpace(0) <= AddressSpace(1));
1187 assert!(AddressSpace(0) == AddressSpace(0));
1188 }
1189}