Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,028 changes: 58 additions & 970 deletions fearless_simd/src/generated/avx2.rs

Large diffs are not rendered by default.

1,770 changes: 679 additions & 1,091 deletions fearless_simd/src/generated/fallback.rs

Large diffs are not rendered by default.

1,188 changes: 32 additions & 1,156 deletions fearless_simd/src/generated/neon.rs

Large diffs are not rendered by default.

720 changes: 0 additions & 720 deletions fearless_simd/src/generated/ops.rs

Large diffs are not rendered by default.

904 changes: 316 additions & 588 deletions fearless_simd/src/generated/simd_trait.rs

Large diffs are not rendered by default.

1,346 changes: 183 additions & 1,163 deletions fearless_simd/src/generated/simd_types.rs

Large diffs are not rendered by default.

970 changes: 39 additions & 931 deletions fearless_simd/src/generated/sse4_2.rs

Large diffs are not rendered by default.

946 changes: 23 additions & 923 deletions fearless_simd/src/generated/wasm.rs

Large diffs are not rendered by default.

9 changes: 5 additions & 4 deletions fearless_simd/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ use crate::{Level, Simd, SimdBase, seal::Seal};

/// Element-wise selection between two SIMD vectors using `self`.
pub trait Select<T: Seal>: Seal {
/// For each element of this mask, select the first operand if the element is all ones, and select the second
/// operand if the element is all zeroes.
/// For each logical lane of this mask, select the first operand if the lane is true, and select the second
/// operand if the lane is false.
///
/// If a mask element is *not* all ones or all zeroes, the result is unspecified. It may vary depending on
/// architecture, feature level, the mask elements' width, the mask vector's width, or library version.
/// Masks may be converted to and from signed integer lane arrays for compatibility with older APIs. For those
/// conversions, false is encoded as all zeroes (integer value 0) and true is encoded as all ones (integer value -1).
/// If a mask is constructed from any other integer bit pattern, the result of this operation is unspecified.
fn select(self, if_true: T, if_false: T) -> T;
}

Expand Down
63 changes: 44 additions & 19 deletions fearless_simd_gen/src/mk_fallback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,17 @@ impl Level for Fallback {
match sig {
OpSig::Splat => {
let num_elements = vec_ty.len;
let normalize_mask = if vec_ty.scalar == ScalarType::Mask {
let scalar = vec_ty.scalar.rust(vec_ty.scalar_bits);
quote! {
let val: #scalar = if val { !0 } else { 0 };
}
} else {
quote! {}
};
quote! {
#method_sig {
#normalize_mask
[val; #num_elements].simd_into(self)
}
}
Expand All @@ -146,7 +155,7 @@ impl Level for Fallback {
let items = make_list(
(0..vec_ty.len)
.map(|idx| {
let args = [quote! { a[#idx] }];
let args = [lane(quote! { a }, vec_ty, idx)];
let expr = fallback::expr(method, vec_ty, &args);
quote! { #expr }
})
Expand All @@ -164,7 +173,8 @@ impl Level for Fallback {
(0..vec_ty.len)
.map(|idx| {
let scalar_ty = target_ty.scalar.rust(target_ty.scalar_bits);
quote! { a[#idx] as #scalar_ty }
let a = lane(quote! { a }, vec_ty, idx);
quote! { #a as #scalar_ty }
})
.collect::<Vec<_>>(),
);
Expand All @@ -179,19 +189,20 @@ impl Level for Fallback {
let items = make_list(
(0..vec_ty.len)
.map(|idx| {
let b_lane = lane(quote! { b }, vec_ty, idx);
let b = if fallback::translate_op(
method,
vec_ty.scalar == ScalarType::Float,
)
.map(rhs_reference)
.unwrap_or(true)
{
quote! { &b[#idx] }
quote! { &#b_lane }
} else {
quote! { b[#idx] }
b_lane
};

let args = [quote! { a[#idx] }, quote! { #b }];
let args = [lane(quote! { a }, vec_ty, idx), quote! { #b }];
let expr = fallback::expr(method, vec_ty, &args);
quote! { #expr }
})
Expand All @@ -208,7 +219,7 @@ impl Level for Fallback {
let items = make_list(
(0..vec_ty.len)
.map(|idx| {
let args = [quote! { a[#idx] }, quote! { shift }];
let args = [lane(quote! { a }, vec_ty, idx), quote! { shift }];
let expr = fallback::expr(method, vec_ty, &args);
quote! { #expr }
})
Expand Down Expand Up @@ -254,7 +265,9 @@ impl Level for Fallback {
let items = make_list(
(0..vec_ty.len)
.map(|idx: usize| {
let args = [quote! { &a[#idx] }, quote! { &b[#idx] }];
let a = lane(quote! { a }, vec_ty, idx);
let b = lane(quote! { b }, vec_ty, idx);
let args = [quote! { &#a }, quote! { &#b }];
let expr = fallback::expr(method, vec_ty, &args);
let mask_ty = mask_type.scalar.rust(vec_ty.scalar_bits);
quote! { -(#expr as #mask_ty) }
Expand All @@ -269,10 +282,14 @@ impl Level for Fallback {
}
}
OpSig::Select => {
let mask_type = vec_ty.mask_ty();
let items = make_list(
(0..vec_ty.len)
.map(|idx| {
quote! { if a[#idx] != 0 { b[#idx] } else { c[#idx] } }
let a = lane(quote! { a }, &mask_type, idx);
let b = lane(quote! { b }, vec_ty, idx);
let c = lane(quote! { c }, vec_ty, idx);
quote! { if #a != 0 { #b } else { #c } }
})
.collect::<Vec<_>>(),
);
Expand Down Expand Up @@ -326,7 +343,9 @@ impl Level for Fallback {
let zip = make_list(
indices
.map(|idx| {
quote! {a[#idx], b[#idx] }
let a = lane(quote! { a }, vec_ty, idx);
let b = lane(quote! { b }, vec_ty, idx);
quote! { #a, #b }
})
.collect::<Vec<_>>(),
);
Expand All @@ -347,12 +366,8 @@ impl Level for Fallback {
let unzip = make_list(
indices
.clone()
.map(|idx| {
quote! {a[#idx]}
})
.chain(indices.map(|idx| {
quote! {b[#idx]}
}))
.map(|idx| lane(quote! { a }, vec_ty, idx))
.chain(indices.map(|idx| lane(quote! { b }, vec_ty, idx)))
.collect::<Vec<_>>(),
);

Expand Down Expand Up @@ -392,7 +407,8 @@ impl Level for Fallback {
let items = make_list(
(0..vec_ty.len)
.map(|idx| {
quote! { a[#idx] as #scalar }
let a = lane(quote! { a }, vec_ty, idx);
quote! { #a as #scalar }
})
.collect::<Vec<_>>(),
);
Expand Down Expand Up @@ -421,7 +437,6 @@ impl Level for Fallback {
quantifier,
condition,
} => {
let indices = (0..vec_ty.len).map(|idx| quote! { #idx });
let check = if condition {
quote! { != }
} else {
Expand All @@ -430,10 +445,12 @@ impl Level for Fallback {

let expr = match quantifier {
crate::ops::Quantifier::Any => {
quote! { #(a[#indices] #check 0)||* }
let lanes = (0..vec_ty.len).map(|idx| lane(quote! { a }, vec_ty, idx));
quote! { #(#lanes #check 0)||* }
}
crate::ops::Quantifier::All => {
quote! { #(a[#indices] #check 0)&&* }
let lanes = (0..vec_ty.len).map(|idx| lane(quote! { a }, vec_ty, idx));
quote! { #(#lanes #check 0)&&* }
}
};

Expand Down Expand Up @@ -540,6 +557,14 @@ fn interleave_indices(
make_list(indices.into_iter().map(func).collect::<Vec<_>>())
}

fn lane(value: TokenStream, vec_ty: &VecType, idx: usize) -> TokenStream {
if vec_ty.scalar == ScalarType::Mask {
quote! { #value.val.0[#idx] }
} else {
quote! { #value[#idx] }
}
}

/// Whether the second argument of the function needs to be passed by reference.
fn rhs_reference(method: &str) -> bool {
!matches!(
Expand Down
9 changes: 9 additions & 0 deletions fearless_simd_gen/src/mk_neon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,18 @@ impl Level for Neon {
match sig {
OpSig::Splat => {
let expr = neon::expr(method, vec_ty, &[quote! { val }]);
let normalize_mask = if vec_ty.scalar == ScalarType::Mask {
let scalar = vec_ty.scalar.rust(vec_ty.scalar_bits);
quote! {
let val: #scalar = if val { !0 } else { 0 };
}
} else {
quote! {}
};
quote! {
#method_sig {
unsafe {
#normalize_mask
#expr.simd_into(self)
}
}
Expand Down
51 changes: 28 additions & 23 deletions fearless_simd_gen/src/mk_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use quote::{format_ident, quote};
use crate::{
generic::generic_op_name,
ops::{CoreOpTrait, OpKind, OpSig, TyFlavor, overloaded_ops_for},
types::{SIMD_TYPES, type_imports},
types::{SIMD_TYPES, ScalarType, type_imports},
};

pub(crate) fn mk_ops() -> TokenStream {
Expand Down Expand Up @@ -85,6 +85,32 @@ pub(crate) fn mk_ops() -> TokenStream {
}
_ => {
let scalar = ty.scalar.rust(ty.scalar_bits);
let scalar_overloads = (ty.scalar != ScalarType::Mask).then(|| {
quote! {
impl<S: Simd> core::ops::#trait_id<#scalar> for #simd<S> {
type Output = Self;
#[inline(always)]
fn #opfn(self, rhs: #scalar) -> Self::Output {
self.simd.#simd_fn(self, rhs.simd_into(self.simd))
}
}

impl<S: Simd> core::ops::#trait_assign_id<#scalar> for #simd<S> {
#[inline(always)]
fn #op_assign_fn(&mut self, rhs: #scalar) {
*self = self.simd.#simd_fn(*self, rhs.simd_into(self.simd));
}
}

impl<S: Simd> core::ops::#trait_id<#simd<S>> for #scalar {
type Output = #simd<S>;
#[inline(always)]
fn #opfn(self, rhs: #simd<S>) -> Self::Output {
rhs.simd.#simd_fn(self.simd_into(rhs.simd), rhs)
}
}
}
});
impls.push(quote! {
impl<S: Simd> core::ops::#trait_id for #simd<S> {
type Output = Self;
Expand All @@ -103,28 +129,7 @@ pub(crate) fn mk_ops() -> TokenStream {
}
}

impl<S: Simd> core::ops::#trait_id<#scalar> for #simd<S> {
type Output = Self;
#[inline(always)]
fn #opfn(self, rhs: #scalar) -> Self::Output {
self.simd.#simd_fn(self, rhs.simd_into(self.simd))
}
}

impl<S: Simd> core::ops::#trait_assign_id<#scalar> for #simd<S> {
#[inline(always)]
fn #op_assign_fn(&mut self, rhs: #scalar) {
*self = self.simd.#simd_fn(*self, rhs.simd_into(self.simd));
}
}

impl<S: Simd> core::ops::#trait_id<#simd<S>> for #scalar {
type Output = #simd<S>;
#[inline(always)]
fn #opfn(self, rhs: #simd<S>) -> Self::Output {
rhs.simd.#simd_fn(self.simd_into(rhs.simd), rhs)
}
}
#scalar_overloads
});
}
}
Expand Down
Loading
Loading