use core::ops::{ Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign, }; use crate::f16::F16; #[rustfmt::skip] // work around for https://github.com/rust-lang/rustfmt/issues/4823 macro_rules! make_float_type { ( #[u32 = $u32:ident] #[bool = $bool:ident] [ $({ #[uint] $uint_smaller:ident; #[int] $int_smaller:ident; $( #[float] $float_smaller:ident; )? },)* ], { #[uint] $uint:ident; #[int] $int:ident; #[float(prim = $float_prim:ident $(, scalar = $float_scalar:ident)?)] $float:ident; }, [ $({ #[uint] $uint_larger:ident; #[int] $int_larger:ident; $( #[float] $float_larger:ident; )? },)* ] ) => { type $float: Float $(+ From)? + Compare + Make $(+ ConvertTo)* $(+ ConvertTo)* $($(+ ConvertTo)?)* + ConvertTo + ConvertTo $(+ ConvertTo)* $(+ ConvertTo)* $($(+ Into)?)*; }; ( #[u32 = $u32:ident] #[bool = $bool:ident] [$($smaller:tt,)*], { #[uint] $uint:ident; #[int] $int:ident; }, [$($larger:tt,)*] ) => {}; } #[rustfmt::skip] // work around for https://github.com/rust-lang/rustfmt/issues/4823 macro_rules! make_uint_int_float_type { ( #[u32 = $u32:ident] #[bool = $bool:ident] [ $({ #[uint($($uint_smaller_traits:tt)*)] $uint_smaller:ident; #[int($($int_smaller_traits:tt)*)] $int_smaller:ident; $( #[float($($float_smaller_traits:tt)*)] $float_smaller:ident; )? },)* ], { #[uint(prim = $uint_prim:ident $(, scalar = $uint_scalar:ident)?)] $uint:ident; #[int(prim = $int_prim:ident $(, scalar = $int_scalar:ident)?)] $int:ident; $( #[float(prim = $float_prim:ident $(, scalar = $float_scalar:ident)?)] $float:ident; )? }, [ $({ #[uint($($uint_larger_traits:tt)*)] $uint_larger:ident; #[int($($int_larger_traits:tt)*)] $int_larger:ident; $( #[float($($float_larger_traits:tt)*)] $float_larger:ident; )? },)* ] ) => { type $uint: UInt $(+ From)? + Compare + Make $(+ ConvertTo)* $(+ ConvertTo)* $($(+ ConvertTo)?)* + ConvertTo $(+ ConvertTo)? $(+ Into)* $(+ Into)* $($(+ Into)?)*; type $int: SInt $(+ From)? + Compare + Make $(+ ConvertTo)* $(+ ConvertTo)* $($(+ ConvertTo)?)* + ConvertTo $(+ ConvertTo)? $(+ ConvertTo)* $(+ Into)* $($(+ Into)?)*; make_float_type! { #[u32 = $u32] #[bool = $bool] [ $({ #[uint] $uint_smaller; #[int] $int_smaller; $( #[float] $float_smaller; )? },)* ], { #[uint] $uint; #[int] $int; $( #[float(prim = $float_prim $(, scalar = $float_scalar)?)] $float; )? }, [ $({ #[uint] $uint_larger; #[int] $int_larger; $( #[float] $float_larger; )? },)* ] } }; } macro_rules! make_uint_int_float_types { ( #[u32 = $u32:ident] #[bool = $bool:ident] [$($smaller:tt,)*], $current:tt, [$first_larger:tt, $($larger:tt,)*] ) => { make_uint_int_float_type! { #[u32 = $u32] #[bool = $bool] [$($smaller,)*], $current, [$first_larger, $($larger,)*] } make_uint_int_float_types! { #[u32 = $u32] #[bool = $bool] [$($smaller,)* $current,], $first_larger, [$($larger,)*] } }; ( #[u32 = $u32:ident] #[bool = $bool:ident] [$($smaller:tt,)*], $current:tt, [] ) => { make_uint_int_float_type! { #[u32 = $u32] #[bool = $bool] [$($smaller,)*], $current, [] } }; } #[rustfmt::skip] // work around for https://github.com/rust-lang/rustfmt/issues/4823 macro_rules! make_types { ( #[bool] $(#[scalar = $ScalarBool:ident])? type $Bool:ident; #[u8] $(#[scalar = $ScalarU8:ident])? type $U8:ident; #[u16] $(#[scalar = $ScalarU16:ident])? type $U16:ident; #[u32] $(#[scalar = $ScalarU32:ident])? type $U32:ident; #[u64] $(#[scalar = $ScalarU64:ident])? type $U64:ident; #[i8] $(#[scalar = $ScalarI8:ident])? type $I8:ident; #[i16] $(#[scalar = $ScalarI16:ident])? type $I16:ident; #[i32] $(#[scalar = $ScalarI32:ident])? type $I32:ident; #[i64] $(#[scalar = $ScalarI64:ident])? type $I64:ident; #[f16] $(#[scalar = $ScalarF16:ident])? type $F16:ident; #[f32] $(#[scalar = $ScalarF32:ident])? type $F32:ident; #[f64] $(#[scalar = $ScalarF64:ident])? type $F64:ident; ) => { type $Bool: Bool $(+ From)? + Make + Select; make_uint_int_float_types! { #[u32 = $U32] #[bool = $Bool] [], { #[uint(prim = u8 $(, scalar = $ScalarU8)?)] $U8; #[int(prim = i8 $(, scalar = $ScalarI8)?)] $I8; }, [ { #[uint(prim = u16 $(, scalar = $ScalarU16)?)] $U16; #[int(prim = i16 $(, scalar = $ScalarI16)?)] $I16; #[float(prim = F16 $(, scalar = $ScalarF16)?)] $F16; }, { #[uint(prim = u32 $(, scalar = $ScalarU32)?)] $U32; #[int(prim = i32 $(, scalar = $ScalarI32)?)] $I32; #[float(prim = f32 $(, scalar = $ScalarF32)?)] $F32; }, { #[uint(prim = u64 $(, scalar = $ScalarU64)?)] $U64; #[int(prim = i64 $(, scalar = $ScalarI64)?)] $I64; #[float(prim = f64 $(, scalar = $ScalarF64)?)] $F64; }, ] } }; } /// reference used to build IR for Kazan; an empty type for `core::simd` pub trait Context: Copy { make_types! { #[bool] type Bool; #[u8] type U8; #[u16] type U16; #[u32] type U32; #[u64] type U64; #[i8] type I8; #[i16] type I16; #[i32] type I32; #[i64] type I64; #[f16] type F16; #[f32] type F32; #[f64] type F64; } make_types! { #[bool] #[scalar = Bool] type VecBool; #[u8] #[scalar = U8] type VecU8; #[u16] #[scalar = U16] type VecU16; #[u32] #[scalar = U32] type VecU32; #[u64] #[scalar = U64] type VecU64; #[i8] #[scalar = I8] type VecI8; #[i16] #[scalar = I16] type VecI16; #[i32] #[scalar = I32] type VecI32; #[i64] #[scalar = I64] type VecI64; #[f16] #[scalar = F16] type VecF16; #[f32] #[scalar = F32] type VecF32; #[f64] #[scalar = F64] type VecF64; } fn make>(self, v: T::Prim) -> T { T::make(self, v) } } pub trait Make: Sized { type Prim; fn make(ctx: Context, v: Self::Prim) -> Self; } pub trait ConvertTo { fn to(self) -> T; } macro_rules! impl_convert_to_using_as { ($($src:ident -> [$($dest:ident),*];)*) => { $($( impl ConvertTo<$dest> for $src { fn to(self) -> $dest { self as $dest } } )*)* }; ([$($src:ident),*] -> $dest:tt;) => { impl_convert_to_using_as! { $( $src -> $dest; )* } }; ([$($src:ident),*];) => { impl_convert_to_using_as! { [$($src),*] -> [$($src),*]; } }; } impl_convert_to_using_as! { [u8, i8, u16, i16, u32, i32, u64, i64, f32, f64]; } pub trait Number: Compare + Add + Sub + Mul + Div + Rem + AddAssign + SubAssign + MulAssign + DivAssign + RemAssign { } impl Number for T where T: Compare + Add + Sub + Mul + Div + Rem + AddAssign + SubAssign + MulAssign + DivAssign + RemAssign { } pub trait BitOps: Copy + BitAnd + BitOr + BitXor + Not + BitAndAssign + BitOrAssign + BitXorAssign { } impl BitOps for T where T: Copy + BitAnd + BitOr + BitXor + Not + BitAndAssign + BitOrAssign + BitXorAssign { } pub trait Int: Number + BitOps + Shl + Shr + ShlAssign + ShrAssign { } pub trait UInt: Int {} pub trait SInt: Int + Neg {} macro_rules! impl_uint { ($($ty:ident),*) => { $( impl Int for $ty {} impl UInt for $ty {} )* }; } impl_uint![u8, u16, u32, u64]; macro_rules! impl_int { ($($ty:ident),*) => { $( impl Int for $ty {} impl SInt for $ty {} )* }; } impl_int![i8, i16, i32, i64]; pub trait Float: Number + Neg { type BitsType: UInt; fn abs(self) -> Self; fn trunc(self) -> Self; fn ceil(self) -> Self; fn floor(self) -> Self; fn round(self) -> Self; #[cfg(feature = "fma")] fn fma(self, a: Self, b: Self) -> Self; fn is_nan(self) -> Self::Bool; fn is_infinite(self) -> Self::Bool; fn is_finite(self) -> Self::Bool; fn from_bits(v: Self::BitsType) -> Self; fn to_bits(self) -> Self::BitsType; } macro_rules! impl_float { ($ty:ty, $bits:ty) => { impl Float for $ty { type BitsType = $bits; fn abs(self) -> Self { #[cfg(feature = "std")] return self.abs(); #[cfg(not(feature = "std"))] todo!(); } fn trunc(self) -> Self { #[cfg(feature = "std")] return self.trunc(); #[cfg(not(feature = "std"))] todo!(); } fn ceil(self) -> Self { #[cfg(feature = "std")] return self.ceil(); #[cfg(not(feature = "std"))] todo!(); } fn floor(self) -> Self { #[cfg(feature = "std")] return self.floor(); #[cfg(not(feature = "std"))] todo!(); } fn round(self) -> Self { #[cfg(feature = "std")] return self.round(); #[cfg(not(feature = "std"))] todo!(); } #[cfg(feature = "fma")] fn fma(self, a: Self, b: Self) -> Self { self.mul_add(a, b) } fn is_nan(self) -> Self::Bool { self.is_nan() } fn is_infinite(self) -> Self::Bool { self.is_infinite() } fn is_finite(self) -> Self::Bool { self.is_finite() } fn from_bits(v: Self::BitsType) -> Self { <$ty>::from_bits(v) } fn to_bits(self) -> Self::BitsType { self.to_bits() } } }; } impl_float!(f32, u32); impl_float!(f64, u64); pub trait Bool: BitOps {} impl Bool for bool {} pub trait Select: Bool { fn select(self, true_v: T, false_v: T) -> T; } impl Select for bool { fn select(self, true_v: T, false_v: T) -> T { if self { true_v } else { false_v } } } pub trait Compare: Copy { type Bool: Bool + Select; fn eq(self, rhs: Self) -> Self::Bool; fn ne(self, rhs: Self) -> Self::Bool; fn lt(self, rhs: Self) -> Self::Bool; fn gt(self, rhs: Self) -> Self::Bool; fn le(self, rhs: Self) -> Self::Bool; fn ge(self, rhs: Self) -> Self::Bool; } macro_rules! impl_compare_using_partial_cmp { ($($ty:ty),*) => { $( impl Compare for $ty { type Bool = bool; fn eq(self, rhs: Self) -> Self::Bool { self == rhs } fn ne(self, rhs: Self) -> Self::Bool { self != rhs } fn lt(self, rhs: Self) -> Self::Bool { self < rhs } fn gt(self, rhs: Self) -> Self::Bool { self > rhs } fn le(self, rhs: Self) -> Self::Bool { self <= rhs } fn ge(self, rhs: Self) -> Self::Bool { self >= rhs } } )* }; } impl_compare_using_partial_cmp![u8, i8, u16, i16, F16, u32, i32, f32, u64, i64, f64];