use std::convert::TryInto;
use std::ops::{Add, BitAnd, BitOr, BitXor, Shl, Shr, Sub};
use wide::{i32x8, i64x4, CmpEq, CmpGt};
pub trait SimdBackend: Copy + 'static {
type Simd: Copy
+ Add<Output = Self::Simd>
+ Sub<Output = Self::Simd>
+ BitAnd<Output = Self::Simd>
+ BitOr<Output = Self::Simd>
+ BitXor<Output = Self::Simd>
+ Shl<Self::Simd, Output = Self::Simd>
+ Shr<Self::Simd, Output = Self::Simd>
+ Shl<i32, Output = Self::Simd>
+ Shr<i32, Output = Self::Simd>
+ Shl<u32, Output = Self::Simd>
+ Shr<u32, Output = Self::Simd>
+ CmpEq<Output = Self::Simd>
+ CmpGt<Output = Self::Simd>;
type Scalar: Copy + PartialEq;
type LaneArray: AsRef<[Self::Scalar]> + AsMut<[Self::Scalar]> + Copy + Default;
const LANES: usize;
const LIMB_BITS: usize;
const CARRY_SHIFT: u32;
const MAX_POSITIVE: Self::Scalar;
fn splat_all_ones() -> Self::Simd;
fn splat_zero() -> Self::Simd;
fn splat_one() -> Self::Simd;
fn splat_scalar(value: Self::Scalar) -> Self::Simd;
fn scalar_from_i64(value: i64) -> Self::Scalar;
fn scalar_from_usize(value: usize) -> Self::Scalar {
Self::scalar_from_i64(value as i64)
}
fn scalar_to_i64(value: Self::Scalar) -> i64;
fn splat_from_i64(value: i64) -> Self::Simd {
Self::splat_scalar(Self::scalar_from_i64(value))
}
fn splat_from_usize(value: usize) -> Self::Simd {
Self::splat_scalar(Self::scalar_from_usize(value))
}
fn mask_word_to_scalar(word: u64) -> Self::Scalar;
fn scalar_to_f32(value: Self::Scalar) -> f32;
fn to_array(vec: Self::Simd) -> Self::LaneArray;
fn from_array(arr: Self::LaneArray) -> Self::Simd;
fn min(lhs: Self::Simd, rhs: Self::Simd) -> Self::Simd;
fn blend(mask: Self::Simd, t: Self::Simd, f: Self::Simd) -> Self::Simd;
}
#[derive(Clone, Copy, Debug, Default)]
pub struct I32x8Backend;
impl SimdBackend for I32x8Backend {
type Simd = i32x8;
type Scalar = i32;
type LaneArray = [i32; 8];
const LANES: usize = 8;
const LIMB_BITS: usize = 32;
const CARRY_SHIFT: u32 = 31;
const MAX_POSITIVE: Self::Scalar = i32::MAX;
#[inline(always)]
fn splat_all_ones() -> Self::Simd {
i32x8::splat(!0)
}
#[inline(always)]
fn splat_zero() -> Self::Simd {
i32x8::splat(0)
}
#[inline(always)]
fn splat_one() -> Self::Simd {
i32x8::splat(1)
}
#[inline(always)]
fn splat_scalar(value: Self::Scalar) -> Self::Simd {
i32x8::splat(value)
}
#[inline(always)]
fn scalar_from_i64(value: i64) -> Self::Scalar {
value.try_into().expect("value does not fit in i32")
}
#[inline(always)]
fn scalar_to_i64(value: Self::Scalar) -> i64 {
value as i64
}
#[inline(always)]
fn mask_word_to_scalar(word: u64) -> Self::Scalar {
word as i32
}
#[inline(always)]
fn scalar_to_f32(value: Self::Scalar) -> f32 {
value as f32
}
#[inline(always)]
fn to_array(vec: Self::Simd) -> Self::LaneArray {
vec.to_array()
}
#[inline(always)]
fn from_array(arr: Self::LaneArray) -> Self::Simd {
i32x8::new(arr)
}
#[inline(always)]
fn min(lhs: Self::Simd, rhs: Self::Simd) -> Self::Simd {
lhs.min(rhs)
}
#[inline(always)]
fn blend(mask: Self::Simd, t: Self::Simd, f: Self::Simd) -> Self::Simd {
mask.blend(t, f)
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct I64x4Backend;
impl SimdBackend for I64x4Backend {
type Simd = i64x4;
type Scalar = i64;
type LaneArray = [i64; 4];
const LANES: usize = 4;
const LIMB_BITS: usize = 64;
const CARRY_SHIFT: u32 = 63;
const MAX_POSITIVE: Self::Scalar = i64::MAX;
#[inline(always)]
fn splat_all_ones() -> Self::Simd {
i64x4::splat(!0)
}
#[inline(always)]
fn splat_zero() -> Self::Simd {
i64x4::splat(0)
}
#[inline(always)]
fn splat_one() -> Self::Simd {
i64x4::splat(1)
}
#[inline(always)]
fn splat_scalar(value: Self::Scalar) -> Self::Simd {
i64x4::splat(value)
}
#[inline(always)]
fn scalar_from_i64(value: i64) -> Self::Scalar {
value
}
#[inline(always)]
fn scalar_to_i64(value: Self::Scalar) -> i64 {
value
}
#[inline(always)]
fn mask_word_to_scalar(word: u64) -> Self::Scalar {
word as i64
}
#[inline(always)]
fn scalar_to_f32(value: Self::Scalar) -> f32 {
value as f64 as f32
}
#[inline(always)]
fn to_array(vec: Self::Simd) -> Self::LaneArray {
vec.to_array()
}
#[inline(always)]
fn from_array(arr: Self::LaneArray) -> Self::Simd {
i64x4::new(arr)
}
#[inline(always)]
fn min(lhs: Self::Simd, rhs: Self::Simd) -> Self::Simd {
lhs.min(rhs)
}
#[inline(always)]
fn blend(mask: Self::Simd, t: Self::Simd, f: Self::Simd) -> Self::Simd {
mask.blend(t, f)
}
}
pub type U32 = I32x8Backend;
pub type U64 = I64x4Backend;
pub type DefaultBackend = U32;