use core::arch::wasm32::*;
use std::{
ops::{Add, Div, Mul, Sub},
slice::from_raw_parts,
};
use crate::{is_shuffle_arg, shuffle_mask, Check, True};
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct Vector {
data: v128,
}
impl Add for Vector {
type Output = Self;
#[inline(always)]
fn add(self, rhs: Self) -> Self {
Self {
data: f32x4_add(self.data, rhs.data),
}
}
}
impl Default for Vector {
#[inline(always)]
fn default() -> Self { Self { data: f32x4_splat(0.0) } }
}
impl Div for Vector {
type Output = Self;
#[inline(always)]
fn div(self, rhs: Self) -> Self {
Self {
data: f32x4_div(self.data, rhs.data),
}
}
}
impl Div<f32> for Vector {
type Output = Self;
#[inline(always)]
fn div(self, rhs: f32) -> Self {
Self {
data: f32x4_div(self.data, f32x4_splat(rhs)),
}
}
}
impl Mul for Vector {
type Output = Self;
#[inline(always)]
fn mul(self, rhs: Self) -> Self {
Self {
data: f32x4_mul(self.data, rhs.data),
}
}
}
impl Mul<f32> for Vector {
type Output = Self;
#[inline(always)]
fn mul(self, rhs: f32) -> Self {
Self {
data: f32x4_mul(self.data, f32x4_splat(rhs)),
}
}
}
impl PartialEq for Vector {
#[inline(always)]
fn eq(&self, other: &Self) -> bool { v128_any_true(f32x4_eq(self.data, other.data)) }
}
impl Sub for Vector {
type Output = Self;
#[inline(always)]
fn sub(self, rhs: Self) -> Self {
Self {
data: f32x4_sub(self.data, rhs.data),
}
}
}
impl Vector {
#[inline(always)]
pub fn new(x: f32, y: f32, z: f32, w: f32) -> Self {
Self {
data: f32x4(x, y, z, w),
}
}
#[inline(always)]
pub fn x(self) -> f32 { f32x4_extract_lane::<0>(self.data) }
#[inline(always)]
pub fn y(self) -> f32 { f32x4_extract_lane::<1>(self.data) }
#[inline(always)]
pub fn z(self) -> f32 { f32x4_extract_lane::<2>(self.data) }
#[inline(always)]
pub fn w(self) -> f32 { f32x4_extract_lane::<3>(self.data) }
#[inline(always)]
pub fn set_x(&mut self, val: f32) { self.data = f32x4_replace_lane::<0>(self.data, val) }
#[inline(always)]
pub fn set_y(&mut self, val: f32) { self.data = f32x4_replace_lane::<1>(self.data, val) }
#[inline(always)]
pub fn set_z(&mut self, val: f32) { self.data = f32x4_replace_lane::<2>(self.data, val) }
#[inline(always)]
pub fn set_w(&mut self, val: f32) { self.data = f32x4_replace_lane::<3>(self.data, val) }
#[inline(always)]
pub fn get(self, idx: u8) -> f32 {
assert!(idx < 4, "Indexed out of Vector bounds");
unsafe { from_raw_parts((&self as *const Vector) as *const f32, 4)[idx as usize] }
}
#[inline(always)]
pub fn shuffle<const X: u32, const Y: u32, const Z: u32, const W: u32>(self) -> Self
where
Check<{ is_shuffle_arg(X, Y, Z, W) }>: True,
[(); shuffle_mask(W, Z, Y, X) as usize]:,
[(); X as usize]:,
[(); Y as usize]:,
[(); Z as usize]:,
[(); W as usize]:,
{
Self {
data: u32x4_shuffle::<{ X as usize }, { Y as usize }, { Z as usize }, { W as usize }>(self.data, self.data),
}
}
#[inline(always)]
pub fn shuffle_merge<const X: u32, const Y: u32, const Z: u32, const W: u32>(vec1: Vector, vec2: Vector) -> Self
where
Check<{ is_shuffle_arg(X, Y, Z, W) }>: True,
[(); shuffle_mask(W, Z, Y, X) as usize]:,
[(); X as usize]:,
[(); Y as usize]:,
[(); Z as usize + 4]:,
[(); W as usize + 4]:,
{
Self {
data: u32x4_shuffle::<{ X as usize }, { Y as usize }, { Z as usize + 4 }, { W as usize + 4 }>(
vec1.data, vec2.data,
),
}
}
#[inline(always)]
pub fn abs(self) -> Self {
Self {
data: unsafe { v128_andnot(self.data, SIGNBITS.vec) },
}
}
#[inline(always)]
pub fn hsum(self) -> f32 {
let shuf = u32x4_shuffle::<1, 0, 3, 2>(self.data, self.data);
let sum = f32x4_add(self.data, shuf);
let shuf = u32x4_shuffle::<2, 1, 2, 1>(sum, sum);
let sum = f32x4_add(sum, shuf);
f32x4_extract_lane::<0>(sum)
}
#[inline(always)]
pub fn min(lhs: Self, rhs: Self) -> Self {
Self {
data: f32x4_min(lhs.data, rhs.data),
}
}
#[inline(always)]
pub fn max(lhs: Self, rhs: Self) -> Self {
Self {
data: f32x4_max(lhs.data, rhs.data),
}
}
#[inline(always)]
pub fn adj_add(lhs: Self, rhs: Self) -> Self {
let a = u32x4_shuffle::<0, 2, 0, 2>(lhs.data, rhs.data);
let b = u32x4_shuffle::<1, 3, 1, 3>(lhs.data, rhs.data);
Self { data: f32x4_add(a, b) }
}
#[inline(always)]
pub fn adj_sub(lhs: Self, rhs: Self) -> Self {
let a = u32x4_shuffle::<0, 2, 0, 2>(lhs.data, rhs.data);
let b = u32x4_shuffle::<1, 3, 1, 3>(lhs.data, rhs.data);
Self { data: f32x4_sub(a, b) }
}
#[inline(always)]
pub fn add_sub(lhs: Self, rhs: Self) -> Self {
let add = f32x4_add(lhs.data, rhs.data);
let add = u32x4_shuffle::<1, 3, 1, 3>(add, add);
let sub = f32x4_sub(lhs.data, rhs.data);
let sub = u32x4_shuffle::<0, 2, 0, 2>(sub, sub);
Self {
data: u32x4_shuffle::<0, 1, 0, 1>(sub, add),
}
}
}
union Bits {
uints: [u32; 4],
vec: v128,
}
const SIGNBITS: Bits = Bits {
uints: [0x80000000, 0x80000000, 0x80000000, 0x80000000],
};