use crate::error::{Error, Result};
+use arbitrary::{size_hint, Arbitrary};
use enum_map::Enum;
use serde::{Deserialize, Serialize};
use std::num::NonZeroU32;
#[derive(
- Serialize, Deserialize, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Enum,
+ Serialize,
+ Deserialize,
+ Copy,
+ Clone,
+ PartialEq,
+ Eq,
+ PartialOrd,
+ Ord,
+ Debug,
+ Hash,
+ Enum,
+ Arbitrary,
)]
#[repr(u8)]
pub enum LocKind {
}
#[derive(
- Serialize, Deserialize, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Enum,
+ Serialize,
+ Deserialize,
+ Copy,
+ Clone,
+ PartialEq,
+ Eq,
+ PartialOrd,
+ Ord,
+ Debug,
+ Hash,
+ Enum,
+ Arbitrary,
)]
#[repr(u8)]
pub enum BaseTy {
Self::Ca | Self::VlMaxvl => nzu32_lit!(1),
}
}
+
+ pub const fn loc_kinds(self) -> &'static [LocKind] {
+ match self {
+ BaseTy::Bits64 => &[LocKind::Gpr, LocKind::StackBits64],
+ BaseTy::Ca => &[LocKind::Ca],
+ BaseTy::VlMaxvl => &[LocKind::VlMaxvl],
+ }
+ }
+
+ pub fn arbitrary_reg_len(
+ self,
+ u: &mut arbitrary::Unstructured<'_>,
+ ) -> arbitrary::Result<NonZeroU32> {
+ Ok(NonZeroU32::new(u.int_in_range(1..=self.max_reg_len().get())?).unwrap())
+ }
+
+ pub fn arbitrary_reg_len_size_hint(depth: usize) -> (usize, Option<usize>) {
+ (0, NonZeroU32::size_hint(depth).1)
+ }
}
validated_fields! {
}
}
+impl<'a> Arbitrary<'a> for TyFields {
+ fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
+ let base_ty: BaseTy = u.arbitrary()?;
+ let reg_len = base_ty.arbitrary_reg_len(u)?;
+ Ok(Self { base_ty, reg_len })
+ }
+ fn size_hint(depth: usize) -> (usize, Option<usize>) {
+ let base_ty = BaseTy::size_hint(depth);
+ let reg_len = BaseTy::arbitrary_reg_len_size_hint(depth);
+ size_hint::and(base_ty, reg_len)
+ }
+}
+
+impl<'a> Arbitrary<'a> for Ty {
+ fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
+ Ok(Ty::new(u.arbitrary()?)?)
+ }
+ fn size_hint(depth: usize) -> (usize, Option<usize>) {
+ TyFields::size_hint(depth)
+ }
+}
+
impl Ty {
pub const fn new(fields: TyFields) -> Result<Ty> {
let TyFields { base_ty, reg_len } = fields;
}
}
+impl<'a> Arbitrary<'a> for LocFields {
+ fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
+ let kind: LocKind = u.arbitrary()?;
+ let reg_len = kind.base_ty().arbitrary_reg_len(u)?;
+ let start = Loc::arbitrary_start(kind, reg_len, u)?;
+ Ok(Self {
+ kind,
+ start,
+ reg_len,
+ })
+ }
+
+ fn size_hint(depth: usize) -> (usize, Option<usize>) {
+ let kind = LocKind::size_hint(depth);
+ let reg_len = BaseTy::arbitrary_reg_len_size_hint(depth);
+ let start = Loc::arbitrary_start_size_hint(depth);
+ size_hint::and(size_hint::and(kind, reg_len), start)
+ }
+}
+
+impl<'a> Arbitrary<'a> for Loc {
+ fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
+ Ok(Loc::new(u.arbitrary()?)?)
+ }
+ fn size_hint(depth: usize) -> (usize, Option<usize>) {
+ LocFields::size_hint(depth)
+ }
+}
+
impl LocFields {
pub const fn ty(self) -> Result<Ty> {
Ty::new(TyFields {
}
impl Loc {
+ pub fn arbitrary_with_ty(
+ ty: Ty,
+ u: &mut arbitrary::Unstructured<'_>,
+ ) -> arbitrary::Result<Self> {
+ let kind = *u.choose(ty.base_ty.loc_kinds())?;
+ let start = Self::arbitrary_start(kind, ty.reg_len, u)?;
+ Ok(Self::new(LocFields {
+ kind,
+ start,
+ reg_len: ty.reg_len,
+ })?)
+ }
+ pub fn arbitrary_start(
+ kind: LocKind,
+ reg_len: NonZeroU32,
+ u: &mut arbitrary::Unstructured<'_>,
+ ) -> arbitrary::Result<u32> {
+ u.int_in_range(0..=Loc::max_start(kind, reg_len)?)
+ }
+ pub fn arbitrary_start_size_hint(depth: usize) -> (usize, Option<usize>) {
+ (0, u32::size_hint(depth).1)
+ }
pub const fn ty(self) -> Ty {
const_unwrap_res!(self.0.ty(), "Loc can only be constructed with valid fields")
}
}),
];
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_base_ty_loc_kinds() {
+ for loc_kind in 0..LocKind::LENGTH {
+ let loc_kind = LocKind::from_usize(loc_kind);
+ let base_ty = loc_kind.base_ty();
+ let loc_kinds = base_ty.loc_kinds();
+ assert!(
+ loc_kinds.contains(&loc_kind),
+ "loc_kind:{loc_kind:?} base_ty:{base_ty:?} loc_kinds:{loc_kinds:?}"
+ );
+ }
+ for base_ty in 0..BaseTy::LENGTH {
+ let base_ty = BaseTy::from_usize(base_ty);
+ let loc_kinds = base_ty.loc_kinds();
+ for &loc_kind in loc_kinds {
+ assert_eq!(
+ loc_kind.base_ty(),
+ base_ty,
+ "loc_kind:{loc_kind:?} base_ty:{base_ty:?} loc_kinds:{loc_kinds:?}"
+ );
+ }
+ }
+ }
+}