590 lines
17 KiB
Text
590 lines
17 KiB
Text
{% import "macros.rs.tera" as macros %}
|
|
|
|
// Generated from {{template_path}} template. Edit the template, not the generated file.
|
|
|
|
{% if scalar_t == "bool" %}
|
|
{% set self_t = "BVec" ~ dim %}
|
|
{% set align = 1 %}
|
|
{% set is_bool = true %}
|
|
{% else %}
|
|
{% set self_t = "BVec" ~ dim ~ "A" %}
|
|
{% if dim == 4 %}
|
|
{% set vec_t = "Vec4" %}
|
|
{% elif dim == 3 %}
|
|
{% set vec_t = "Vec3A" %}
|
|
{% endif %}
|
|
{% set align = 16 %}
|
|
{% set is_u32 = true %}
|
|
{% if is_sse2 %}
|
|
{% set simd_t = "__m128" %}
|
|
{% elif is_wasm32 %}
|
|
{% set simd_t = "v128" %}
|
|
{% elif is_neon %}
|
|
{% set simd_t = "uint32x4_t" %}
|
|
{% elif is_coresimd %}
|
|
{% set simd_t = "mask32x4" %}
|
|
{% endif %}
|
|
{% endif %}
|
|
|
|
{% set components = ["x", "y", "z", "w"] | slice(end = dim) %}
|
|
|
|
use core::fmt;
|
|
use core::ops::*;
|
|
|
|
{% if is_sse2 %}
|
|
#[cfg(target_arch = "x86")]
|
|
use core::arch::x86::*;
|
|
#[cfg(target_arch = "x86_64")]
|
|
use core::arch::x86_64::*;
|
|
{% elif is_wasm32 %}
|
|
use core::arch::wasm32::*;
|
|
{% elif is_neon %}
|
|
use core::arch::aarch64::*;
|
|
{% elif is_coresimd %}
|
|
use core::simd::*;
|
|
{% endif %}
|
|
|
|
{% if is_sse2 or is_neon or is_coresimd %}
|
|
#[repr(C)]
|
|
union UnionCast {
|
|
a: [u32; 4],
|
|
v: {{ self_t }}
|
|
}
|
|
{% endif %}
|
|
|
|
/// Creates a {{ dim }}-dimensional `bool` vector mask.
|
|
#[inline(always)]
|
|
#[must_use]
|
|
pub const fn {{ self_t | lower }}(
|
|
{% for c in components %}
|
|
{{ c }}: bool,
|
|
{% endfor %}
|
|
) -> {{ self_t }} {
|
|
{{ self_t }}::new({{ components | join(sep=",") }})
|
|
}
|
|
|
|
{% if is_scalar and is_bool %}
|
|
/// A {{ dim }}-dimensional `bool` vector mask.
|
|
{%- elif is_scalar and is_u32 %}
|
|
/// A {{ dim }}-dimensional `u32` vector mask.
|
|
{%- else %}
|
|
/// A {{ dim }}-dimensional SIMD vector mask.
|
|
///
|
|
/// This type is {{ align }} byte aligned.
|
|
{%- endif %}
|
|
{%- if is_scalar or is_bool %}
|
|
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
|
{%- else %}
|
|
#[derive(Clone, Copy)]
|
|
{%- endif %}
|
|
{%- if is_scalar %}
|
|
#[repr(C, align({{ align }}))]
|
|
#[cfg_attr(target_arch = "spirv", rust_gpu::vector::v1)]
|
|
pub struct {{ self_t }}
|
|
{
|
|
{% for c in components %}
|
|
pub {{ c }}: {{ scalar_t }},
|
|
{%- endfor %}
|
|
}
|
|
{%- else %}
|
|
#[repr(transparent)]
|
|
pub struct {{ self_t }}(pub(crate) {{ simd_t }});
|
|
{% endif %}
|
|
|
|
const MASK: [u32; 2] = [0, 0xff_ff_ff_ff];
|
|
|
|
impl {{ self_t }} {
|
|
/// All false.
|
|
pub const FALSE: Self = Self::splat(false);
|
|
|
|
/// All true.
|
|
pub const TRUE: Self = Self::splat(true);
|
|
|
|
/// Creates a new vector mask.
|
|
#[inline(always)]
|
|
#[must_use]
|
|
pub const fn new(
|
|
{% for c in components %}
|
|
{{ c }}: bool,
|
|
{% endfor %}
|
|
) -> Self {
|
|
{% if is_scalar and is_bool %}
|
|
Self {
|
|
{% for c in components %}
|
|
{{ c }},
|
|
{%- endfor %}
|
|
}
|
|
{% elif is_scalar and is_u32 %}
|
|
Self {
|
|
{% for c in components %}
|
|
{{ c }}: MASK[{{ c }} as usize],
|
|
{%- endfor %}
|
|
}
|
|
{% elif is_sse2 or is_neon or is_coresimd %}
|
|
unsafe {
|
|
UnionCast { a: [
|
|
MASK[x as usize],
|
|
MASK[y as usize],
|
|
MASK[z as usize],
|
|
{% if dim == 3 %}
|
|
0,
|
|
{% elif dim == 4 %}
|
|
MASK[w as usize],
|
|
{% endif %}
|
|
] }.v
|
|
}
|
|
{% elif is_wasm32 %}
|
|
Self(u32x4(
|
|
MASK[x as usize],
|
|
MASK[y as usize],
|
|
MASK[z as usize],
|
|
{% if dim == 3 %}
|
|
0,
|
|
{% elif dim == 4 %}
|
|
MASK[w as usize],
|
|
{% endif %}
|
|
))
|
|
{% endif %}
|
|
}
|
|
|
|
/// Creates a vector mask with all elements set to `v`.
|
|
#[inline]
|
|
#[must_use]
|
|
pub const fn splat(v: bool) -> Self {
|
|
Self::new(
|
|
{% for c in components %}
|
|
v,
|
|
{%- endfor %}
|
|
)
|
|
}
|
|
|
|
/// Creates a new vector mask from a bool array.
|
|
#[inline]
|
|
#[must_use]
|
|
pub const fn from_array(a: [bool; {{ dim }}]) -> Self {
|
|
Self::new(
|
|
{% for c in components %}
|
|
a[{{ loop.index0 }}],
|
|
{%- endfor %}
|
|
)
|
|
}
|
|
|
|
/// Returns a bitmask with the lowest {{ dim }} bits set from the elements of `self`.
|
|
///
|
|
/// A true element results in a `1` bit and a false element in a `0` bit. Element `x` goes
|
|
/// into the first lowest bit, element `y` into the second, etc.
|
|
#[inline]
|
|
#[must_use]
|
|
pub fn bitmask(self) -> u32 {
|
|
{% if is_scalar and is_bool %}
|
|
{% for c in components %}
|
|
{% if loop.first %}
|
|
(self.{{ c }} as u32) |
|
|
{% else %}
|
|
((self.{{ c }} as u32) << {{ loop.index0 }}) {% if not loop.last %} | {% endif %}
|
|
{% endif %}
|
|
{% endfor %}
|
|
{% elif is_scalar and is_u32 %}
|
|
{% for c in components %}
|
|
{% if loop.first %}
|
|
(self.{{ c }} & 0x1) |
|
|
{% else %}
|
|
((self.{{ c }} & 0x1) << {{ loop.index0 }}) {% if not loop.last %} | {% endif %}
|
|
{% endif %}
|
|
{% endfor %}
|
|
{% elif is_sse2 %}
|
|
{% if dim == 3 %}
|
|
unsafe { (_mm_movemask_ps(self.0) as u32) & 0x7 }
|
|
{% elif dim == 4 %}
|
|
unsafe { _mm_movemask_ps(self.0) as u32 }
|
|
{% endif %}
|
|
{% elif is_wasm32 %}
|
|
{% if dim == 3 %}
|
|
(u32x4_bitmask(self.0) & 0x7) as u32
|
|
{% elif dim == 4 %}
|
|
u32x4_bitmask(self.0) as u32
|
|
{% endif %}
|
|
{% elif is_neon %}
|
|
{% if dim == 3 %}
|
|
let movemask = unsafe {
|
|
{% elif dim == 4 %}
|
|
unsafe {
|
|
{% endif %}
|
|
let mma = vandq_u32(self.0, vld1q_u32([1, 2, 4, 8].as_ptr())); // [0 1 2 3]
|
|
let mmb = vextq_u32(mma, mma, 2); // [2 3 0 1]
|
|
let mmc = vorrq_u32(mma, mmb); // [0+2 1+3 0+2 1+3]
|
|
let mmd = vextq_u32(mmc, mmc, 3); // [1+3 0+2 1+3 0+2]
|
|
let mme = vorrq_u32(mmc, mmd); // [0+1+2+3 ...]
|
|
vgetq_lane_u32(mme, 0)
|
|
{% if dim == 3 %}
|
|
};
|
|
|
|
movemask & 0x7
|
|
{% elif dim == 4 %}
|
|
}
|
|
{% endif %}
|
|
{% elif is_coresimd %}
|
|
{% if dim == 3 %}
|
|
(self.0.to_bitmask() & 0x7) as u32
|
|
{% elif dim == 4 %}
|
|
self.0.to_bitmask() as u32
|
|
{% endif %}
|
|
{% else %}
|
|
unimplemented!()
|
|
{% endif %}
|
|
}
|
|
|
|
/// Returns true if any of the elements are true, false otherwise.
|
|
#[inline]
|
|
#[must_use]
|
|
pub fn any(self) -> bool {
|
|
{% if is_scalar and is_bool %}
|
|
{% for c in components %}
|
|
self.{{ c }} {% if not loop.last %} || {% endif %}
|
|
{%- endfor %}
|
|
{% elif is_scalar and is_u32 %}
|
|
((
|
|
{% for c in components %}
|
|
self.{{ c }} {% if not loop.last %} | {% endif %}
|
|
{%- endfor %}
|
|
) & 0x1) != 0
|
|
{% else %}
|
|
self.bitmask() != 0
|
|
{% endif %}
|
|
}
|
|
|
|
/// Returns true if all the elements are true, false otherwise.
|
|
#[inline]
|
|
#[must_use]
|
|
pub fn all(self) -> bool {
|
|
{% if is_scalar and is_bool %}
|
|
{% for c in components %}
|
|
self.{{ c }} {% if not loop.last %} && {% endif %}
|
|
{%- endfor %}
|
|
{% elif is_scalar and is_u32 %}
|
|
((
|
|
{% for c in components %}
|
|
self.{{ c }} {% if not loop.last %} & {% endif %}
|
|
{%- endfor %}
|
|
) & 0x1) != 0
|
|
{% else %}
|
|
{% if dim == 3 %}
|
|
self.bitmask() == 0x7
|
|
{% elif dim == 4 %}
|
|
self.bitmask() == 0xf
|
|
{% endif %}
|
|
{% endif %}
|
|
}
|
|
|
|
/// Tests the value at `index`.
|
|
///
|
|
/// Panics if `index` is greater than {{ dim - 1 }}.
|
|
#[inline]
|
|
#[must_use]
|
|
pub fn test(&self, index: usize) -> bool {
|
|
{% if is_coresimd %}
|
|
assert!(index < {{ dim }}, "index out of bounds");
|
|
self.0.test(index)
|
|
{% else %}
|
|
match index {
|
|
{% for c in components %}
|
|
{%- if is_scalar and is_bool %}
|
|
{{ loop.index0 }} => self.{{ c }},
|
|
{%- elif is_scalar and is_u32 %}
|
|
{{ loop.index0 }} => (self.{{ c }} & 0x1) != 0,
|
|
{%- else %}
|
|
{{ loop.index0 }} => (self.bitmask() & (1 << {{ loop.index0 }})) != 0,
|
|
{%- endif %}
|
|
{%- endfor %}
|
|
_ => panic!("index out of bounds")
|
|
}
|
|
{% endif %}
|
|
}
|
|
|
|
/// Sets the element at `index`.
|
|
///
|
|
/// Panics if `index` is greater than {{ dim - 1 }}.
|
|
#[inline]
|
|
pub fn set(&mut self, index: usize, value: bool) {
|
|
{% if is_scalar %}
|
|
match index {
|
|
{% for c in components %}
|
|
{%- if is_bool %}
|
|
{{ loop.index0 }} => self.{{ c }} = value,
|
|
{%- elif is_u32 %}
|
|
{{ loop.index0 }} => self.{{ c }} = MASK[value as usize],
|
|
{%- endif %}
|
|
{%- endfor %}
|
|
_ => panic!("index out of bounds")
|
|
}
|
|
{% elif is_coresimd %}
|
|
{% if dim < 4 %}
|
|
assert!(index < {{ dim }}, "index out of bounds");
|
|
{%- endif %}
|
|
self.0.set(index, value)
|
|
{% elif is_neon %}
|
|
self.0 = match index {
|
|
{% for c in components %}
|
|
{{ loop.index0 }} => unsafe {
|
|
vsetq_lane_u32(MASK[value as usize], self.0, {{ loop.index0 }})
|
|
},
|
|
{%- endfor %}
|
|
_ => panic!("index out of bounds")
|
|
}
|
|
{% else %}
|
|
use crate::{{ vec_t }};
|
|
let mut v = {{ vec_t }}(self.0);
|
|
v[index] = f32::from_bits(MASK[value as usize]);
|
|
self.0 = v.0;
|
|
{% endif %}
|
|
}
|
|
|
|
#[inline]
|
|
#[must_use]
|
|
fn into_bool_array(self) -> [bool; {{ dim }}] {
|
|
{% if is_scalar and is_bool %}
|
|
[
|
|
{% for c in components %}
|
|
self.{{ c }},
|
|
{%- endfor %}
|
|
]
|
|
{% elif is_scalar and is_u32 %}
|
|
[
|
|
{% for c in components %}
|
|
(self.{{ c }} & 0x1) != 0,
|
|
{%- endfor %}
|
|
]
|
|
{% else %}
|
|
{% set bits = [1, 2, 4, 8] | slice(end = dim) %}
|
|
let bitmask = self.bitmask();
|
|
[
|
|
{% for b in bits %}
|
|
(bitmask & {{ b }}) != 0,
|
|
{%- endfor %}
|
|
]
|
|
{% endif %}
|
|
}
|
|
|
|
#[inline]
|
|
#[must_use]
|
|
fn into_u32_array(self) -> [u32; {{ dim }}] {
|
|
{% if is_scalar and is_bool %}
|
|
[
|
|
{% for c in components %}
|
|
MASK[self.{{ c }} as usize],
|
|
{%- endfor %}
|
|
]
|
|
{% elif is_scalar and is_u32 %}
|
|
[
|
|
{% for c in components %}
|
|
self.{{ c }},
|
|
{%- endfor %}
|
|
]
|
|
{% else %}
|
|
let bitmask = self.bitmask();
|
|
[
|
|
{% for c in components %}
|
|
{% if loop.first %}
|
|
MASK[(bitmask & 1) as usize],
|
|
{% else %}
|
|
MASK[((bitmask >> {{ loop.index0 }}) & 1) as usize],
|
|
{% endif %}
|
|
{%- endfor %}
|
|
]
|
|
{% endif %}
|
|
}
|
|
}
|
|
|
|
|
|
impl Default for {{ self_t }} {
|
|
#[inline]
|
|
fn default() -> Self {
|
|
Self::FALSE
|
|
}
|
|
}
|
|
|
|
{% if not is_scalar and not is_bool %}
|
|
impl PartialEq for {{ self_t }} {
|
|
#[inline]
|
|
fn eq(&self, rhs: &Self) -> bool {
|
|
self.bitmask().eq(&rhs.bitmask())
|
|
}
|
|
}
|
|
|
|
impl Eq for {{ self_t }} {}
|
|
|
|
impl core::hash::Hash for {{ self_t }} {
|
|
#[inline]
|
|
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
|
self.bitmask().hash(state);
|
|
}
|
|
}
|
|
{%- endif %}
|
|
|
|
impl BitAnd for {{ self_t }} {
|
|
type Output = Self;
|
|
#[inline]
|
|
fn bitand(self, rhs: Self) -> Self {
|
|
{% if is_scalar %}
|
|
Self {
|
|
{% for c in components %}
|
|
{{ c }}: self.{{ c }} & rhs.{{ c }},
|
|
{%- endfor %}
|
|
}
|
|
{% elif is_sse2 %}
|
|
Self(unsafe { _mm_and_ps(self.0, rhs.0) })
|
|
{% elif is_wasm32 %}
|
|
Self(v128_and(self.0, rhs.0))
|
|
{% elif is_neon %}
|
|
Self(unsafe { vandq_u32(self.0, rhs.0) })
|
|
{% elif is_coresimd %}
|
|
Self(self.0 & rhs.0)
|
|
{% else %}
|
|
unimplemented!()
|
|
{% endif %}
|
|
}
|
|
}
|
|
|
|
{{ macros::impl_ref_binop(imp="BitAnd", self_t=self_t, rhs_t=self_t, output_t=self_t) }}
|
|
|
|
{{ macros::impl_op_assign(imp="BitAnd", self_t=self_t, rhs_t=self_t) }}
|
|
|
|
impl BitOr for {{ self_t }} {
|
|
type Output = Self;
|
|
#[inline]
|
|
fn bitor(self, rhs: Self) -> Self {
|
|
{% if is_scalar %}
|
|
Self {
|
|
{% for c in components %}
|
|
{{ c }}: self.{{ c }} | rhs.{{ c }},
|
|
{%- endfor %}
|
|
}
|
|
{% elif is_sse2 %}
|
|
Self(unsafe { _mm_or_ps(self.0, rhs.0) })
|
|
{% elif is_wasm32 %}
|
|
Self(v128_or(self.0, rhs.0))
|
|
{% elif is_neon %}
|
|
Self(unsafe { vorrq_u32(self.0, rhs.0) })
|
|
{% elif is_coresimd %}
|
|
Self(self.0 | rhs.0)
|
|
{% else %}
|
|
unimplemented!()
|
|
{% endif %}
|
|
}
|
|
}
|
|
|
|
{{ macros::impl_ref_binop(imp="BitOr", self_t=self_t, rhs_t=self_t, output_t=self_t) }}
|
|
|
|
{{ macros::impl_op_assign(imp="BitOr", self_t=self_t, rhs_t=self_t) }}
|
|
|
|
impl BitXor for {{ self_t }} {
|
|
type Output = Self;
|
|
#[inline]
|
|
fn bitxor(self, rhs: Self) -> Self {
|
|
{% if is_scalar %}
|
|
Self {
|
|
{% for c in components %}
|
|
{{ c }}: self.{{ c }} ^ rhs.{{ c }},
|
|
{%- endfor %}
|
|
}
|
|
{% elif is_sse2 %}
|
|
Self(unsafe { _mm_xor_ps(self.0, rhs.0) })
|
|
{% elif is_wasm32 %}
|
|
Self(v128_xor(self.0, rhs.0))
|
|
{% elif is_neon %}
|
|
Self(unsafe { veorq_u32(self.0, rhs.0) })
|
|
{% elif is_coresimd %}
|
|
Self(self.0 ^ rhs.0)
|
|
{% else %}
|
|
unimplemented!()
|
|
{% endif %}
|
|
}
|
|
}
|
|
|
|
{{ macros::impl_ref_binop(imp="BitXor", self_t=self_t, rhs_t=self_t, output_t=self_t) }}
|
|
|
|
{{ macros::impl_op_assign(imp="BitXor", self_t=self_t, rhs_t=self_t) }}
|
|
|
|
impl Not for {{ self_t }} {
|
|
type Output = Self;
|
|
#[inline]
|
|
fn not(self) -> Self {
|
|
{% if is_scalar %}
|
|
Self {
|
|
{% for c in components %}
|
|
{{ c }}: !self.{{ c }},
|
|
{%- endfor %}
|
|
}
|
|
{% elif is_sse2 %}
|
|
Self(unsafe {
|
|
_mm_andnot_ps(self.0, _mm_set_ps1(f32::from_bits(0xff_ff_ff_ff)))
|
|
})
|
|
{% elif is_wasm32 %}
|
|
Self(v128_not(self.0))
|
|
{% elif is_neon %}
|
|
Self(unsafe { vmvnq_u32(self.0) })
|
|
{% elif is_coresimd %}
|
|
Self(!self.0)
|
|
{% else %}
|
|
unimplemented!()
|
|
{% endif %}
|
|
}
|
|
}
|
|
|
|
{{ macros::impl_ref_unop(imp="Not", self_t=self_t, output_t=self_t) }}
|
|
|
|
{% if not is_scalar %}
|
|
impl From<{{ self_t }}> for {{ simd_t }} {
|
|
#[inline]
|
|
fn from(t: {{ self_t }}) -> Self {
|
|
t.0
|
|
}
|
|
}
|
|
{% endif %}
|
|
|
|
impl fmt::Debug for {{ self_t }} {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
let arr = self.into_u32_array();
|
|
{%- if dim == 2 %}
|
|
write!(f, "{}({:#x}, {:#x})", stringify!({{ self_t }}), arr[0], arr[1])
|
|
{% elif dim == 3 %}
|
|
write!(f, "{}({:#x}, {:#x}, {:#x})", stringify!({{ self_t }}), arr[0], arr[1], arr[2])
|
|
{% elif dim == 4 %}
|
|
write!(f, "{}({:#x}, {:#x}, {:#x}, {:#x})", stringify!({{ self_t }}), arr[0], arr[1], arr[2], arr[3])
|
|
{% endif %}
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for {{ self_t }} {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
let arr = self.into_bool_array();
|
|
{%- if dim == 2 %}
|
|
write!(f, "[{}, {}]", arr[0], arr[1])
|
|
{% elif dim == 3 %}
|
|
write!(f, "[{}, {}, {}]", arr[0], arr[1], arr[2])
|
|
{% elif dim == 4 %}
|
|
write!(f, "[{}, {}, {}, {}]", arr[0], arr[1], arr[2], arr[3])
|
|
{% endif %}
|
|
}
|
|
}
|
|
|
|
impl From<[bool; {{ dim }}]> for {{ self_t }} {
|
|
#[inline]
|
|
fn from(a: [bool; {{ dim }}]) -> Self {
|
|
Self::from_array(a)
|
|
}
|
|
}
|
|
|
|
impl From<{{ self_t }}> for [bool; {{ dim }}] {
|
|
#[inline]
|
|
fn from(mask: {{ self_t }}) -> Self {
|
|
mask.into_bool_array()
|
|
}
|
|
}
|
|
|
|
impl From<{{ self_t }}> for [u32; {{ dim }}] {
|
|
#[inline]
|
|
fn from(mask: {{ self_t }}) -> Self {
|
|
mask.into_u32_array()
|
|
}
|
|
}
|