use std::mem::transmute;
use rand::Rng;
use tuple::*;
use real::Real;
macro_rules! call {
($pre:ident, $name:ident, $post:ident ( $($arg:expr),* ) ) => (
unsafe {
use std::arch::x86_64::*;
transmute(concat_idents!($pre, $name, $post)( $( transmute($arg) ),* ))
}
)
}
macro_rules! impl_simd {
($($size:tt, $simd:ident: $scalar:ident, $bool:ty, $pre:ident ~ $post:ident, $Tuple:ident($($idx:tt)*));*) => ( $(
impl Real for $simd {
const PI: Self = $simd::splat(::std::$scalar::consts::PI);
type Bool = $bool;
type Scalar = $scalar;
type Iterator = IntoElements<$Tuple<$(first_t!($scalar, $idx)),*>>;
#[inline(always)]
fn splat(s: Self::Scalar) -> Self {
$simd::splat(s)
}
#[inline(always)]
fn values(self) -> Self::Iterator {
#[repr(align($size))]
struct Arr([$scalar; 0$(+ first_e!(1, $idx))*]);
let mut arr = Arr([$(first_e!(0., $idx)),*]);
self.store(&mut arr.0, 0);
$Tuple::from(arr.0).into_elements()
}
#[inline(always)]
fn int(v: i16) -> Self { Self::splat($scalar::from(v)) }
#[inline]
fn float(f: f64) -> Self {
let f = f as $scalar;
Self::splat($scalar::from(f))
}
#[inline]
fn frac(nom: i16, denom: u16) -> Self {
Self::splat($scalar::from(nom) / $scalar::from(denom))
}
#[inline(always)]
fn wrap(self, at: Self, span: Self) -> Self {
Real::select(self - span, self, self.gt(at))
}
fn uniform01<R: Rng>(rng: &mut R) -> Self {
$simd::new($(first_e!(rng.gen(), $idx)),*)
}
#[inline(always)]
fn abs(self) -> Self {
Real::select(-self, self, self.le(Self::splat(0.0)))
}
#[inline(always)]
fn sqrt(self) -> Self {
call!($pre, sqrt, $post (self))
}
#[inline(always)]
fn floor(self) -> Self {
call!($pre, floor, $post (self))
}
#[inline(always)]
fn ceil(self) -> Self {
call!($pre, ceil, $post (self))
}
#[inline(always)]
fn min(self, other: Self) -> Self {
call!($pre, min, $post (self, other))
}
#[inline(always)]
fn max(self, other: Self) -> Self {
call!($pre, max, $post (self, other))
}
#[inline(always)]
fn lt(self, rhs: Self) -> Self::Bool { $simd::lt(self, rhs) }
#[inline(always)]
fn le(self, rhs: Self) -> Self::Bool { $simd::le(self, rhs) }
#[inline(always)]
fn gt(self, rhs: Self) -> Self::Bool { $simd::gt(self, rhs) }
#[inline(always)]
fn ge(self, rhs: Self) -> Self::Bool { $simd::ge(self, rhs) }
#[inline(always)]
fn eq(self, rhs: Self) -> Self::Bool { $simd::eq(self, rhs) }
#[inline(always)]
fn select(self, other: Self, cond: Self::Bool) -> Self {
call!($pre, blendv, $post (self, other, cond))
}
}
)* )
}
use simd_::*;
impl_simd!(16, f32x4: f32, bool32fx4, _mm_ ~ _ps, T4(0 1 2 3));
#[cfg(target_feature = "sse2")]
use simd_::x86::sse2::*;
#[cfg(target_feature = "sse2")]
impl_simd!(16, f64x2: f64, bool64fx2, _mm_ ~ _pd, T2(0 1));
#[cfg(target_feature = "avx")]
use simd_::x86::avx::*;
#[cfg(target_feature = "avx")]
impl_simd!(
32, f32x8: f32, bool32fx8, _mm256_ ~ _ps, T8(0 1 2 3 4 5 6 7);
32, f64x4: f64, bool64fx4, _mm256_ ~ _pd, T4(0 1 2 3)
);