Skip to content

Commit 5b83500

Browse files
committed
Introduce SimdCvt trait family
1 parent 4103a95 commit 5b83500

File tree

10 files changed

+138
-12
lines changed

10 files changed

+138
-12
lines changed

fearless_simd/src/generated/fallback.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// This file is autogenerated by fearless_simd_gen
22

3-
use crate::{Level, Simd, SimdInto, seal::Seal};
3+
use crate::{Level, Simd, SimdCvtFloat, SimdCvtTruncate, SimdInto, seal::Seal};
44
use crate::{
55
f32x4, f32x8, f32x16, i8x16, i8x32, i8x64, i16x8, i16x16, i16x32, i32x4, i32x8, i32x16,
66
mask8x16, mask8x32, mask8x64, mask16x8, mask16x16, mask16x32, mask32x4, mask32x8, mask32x16,
@@ -4887,3 +4887,21 @@ impl Simd for Fallback {
48874887
(b0.simd_into(self), b1.simd_into(self))
48884888
}
48894889
}
4890+
impl SimdCvtTruncate<f32x4<Fallback>> for u32x4<Fallback> {
4891+
#[inline(always)]
4892+
fn truncate_from(x: f32x4<Fallback>) -> Self {
4893+
Self {
4894+
val: x.val.map(|e| e as u32),
4895+
simd: x.simd,
4896+
}
4897+
}
4898+
}
4899+
impl SimdCvtFloat<u32x4<Fallback>> for f32x4<Fallback> {
4900+
#[inline(always)]
4901+
fn float_from(x: u32x4<Fallback>) -> Self {
4902+
Self {
4903+
val: x.val.map(|e| e as f32),
4904+
simd: x.simd,
4905+
}
4906+
}
4907+
}

fearless_simd/src/generated/neon.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// This file is autogenerated by fearless_simd_gen
22

3-
use crate::{Level, Simd, SimdFrom, SimdInto, seal::Seal};
3+
use crate::{Level, Simd, SimdCvtFloat, SimdCvtTruncate, SimdFrom, SimdInto, seal::Seal};
44
use crate::{
55
f32x4, f32x8, f32x16, i8x16, i8x32, i8x64, i16x8, i16x16, i16x32, i32x4, i32x8, i32x16,
66
mask8x16, mask8x32, mask8x64, mask16x8, mask16x16, mask16x32, mask32x4, mask32x8, mask32x16,
@@ -3166,6 +3166,18 @@ impl Simd for Neon {
31663166
(b0.simd_into(self), b1.simd_into(self))
31673167
}
31683168
}
3169+
impl SimdCvtTruncate<f32x4<Neon>> for u32x4<Neon> {
3170+
#[inline(always)]
3171+
fn truncate_from(x: f32x4<Neon>) -> Self {
3172+
unsafe { vcvtq_u32_f32(x.into()).simd_into(x.simd) }
3173+
}
3174+
}
3175+
impl SimdCvtFloat<u32x4<Neon>> for f32x4<Neon> {
3176+
#[inline(always)]
3177+
fn float_from(x: u32x4<Neon>) -> Self {
3178+
unsafe { vcvt_f32_u32(x.into).simd_into(x.simd) }
3179+
}
3180+
}
31693181
impl<S: Simd> SimdFrom<float32x4_t, S> for f32x4<S> {
31703182
#[inline(always)]
31713183
fn simd_from(arch: float32x4_t, simd: S) -> Self {

fearless_simd/src/generated/simd_trait.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
// This file is autogenerated by fearless_simd_gen
22

3-
use crate::{Level, SimdElement, SimdInto, seal::Seal};
3+
use crate::{Level, SimdCvtFloat, SimdCvtTruncate, SimdElement, SimdInto, seal::Seal};
44
use crate::{
55
f32x4, f32x8, f32x16, i8x16, i8x32, i8x64, i16x8, i16x16, i16x32, i32x4, i32x8, i32x16,
66
mask8x16, mask8x32, mask8x64, mask16x8, mask16x16, mask16x32, mask32x4, mask32x8, mask32x16,
77
u8x16, u8x32, u8x64, u16x8, u16x16, u16x32, u32x4, u32x8, u32x16,
88
};
99
#[doc = r" TODO: docstring"]
1010
pub trait Simd: Sized + Clone + Copy + Send + Sync + Seal + 'static {
11-
type f32s: SimdFloat<f32, Self, Block = f32x4<Self>>;
11+
type f32s: SimdFloat<f32, Self, Block = f32x4<Self>> + SimdCvtFloat<Self::u32s>;
1212
type u8s: SimdInt<u8, Self, Block = u8x16<Self>>;
1313
type i8s: SimdInt<i8, Self, Block = i8x16<Self>>;
1414
type u16s: SimdInt<u16, Self, Block = u16x8<Self>>;
1515
type i16s: SimdInt<i16, Self, Block = i16x8<Self>>;
16-
type u32s: SimdInt<u32, Self, Block = u32x4<Self>>;
16+
type u32s: SimdInt<u32, Self, Block = u32x4<Self>> + SimdCvtTruncate<Self::f32s>;
1717
type i32s: SimdInt<i32, Self, Block = i32x4<Self>>;
1818
type mask8s: SimdMask<i8, Self, Block = mask8x16<Self>>;
1919
type mask16s: SimdMask<i16, Self, Block = mask16x8<Self>>;
@@ -661,6 +661,10 @@ pub trait SimdFloat<Element: SimdElement, S: Simd>:
661661
+ core::ops::Div<Output = Self>
662662
+ core::ops::Div<Element, Output = Self>
663663
{
664+
#[inline(always)]
665+
fn cvt_trunc<T: SimdCvtTruncate<Self>>(self) -> T {
666+
T::truncate_from(self)
667+
}
664668
fn abs(self) -> Self;
665669
fn sqrt(self) -> Self;
666670
fn copysign(self, rhs: impl SimdInto<Self, S>) -> Self;
@@ -696,6 +700,10 @@ pub trait SimdInt<Element: SimdElement, S: Simd>:
696700
+ core::ops::BitXor<Output = Self>
697701
+ core::ops::BitXor<Element, Output = Self>
698702
{
703+
#[inline(always)]
704+
fn cvt_float<T: SimdCvtFloat<Self>>(self) -> T {
705+
T::float_from(self)
706+
}
699707
fn simd_eq(self, rhs: impl SimdInto<Self, S>) -> Self::Mask;
700708
fn simd_lt(self, rhs: impl SimdInto<Self, S>) -> Self::Mask;
701709
fn simd_le(self, rhs: impl SimdInto<Self, S>) -> Self::Mask;

fearless_simd/src/generated/wasm.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// This file is autogenerated by fearless_simd_gen
22

3-
use crate::{Level, Simd, SimdFrom, SimdInto, seal::Seal};
3+
use crate::{Level, Simd, SimdCvtFloat, SimdCvtTruncate, SimdFrom, SimdInto, seal::Seal};
44
use crate::{
55
f32x4, f32x8, f32x16, i8x16, i8x32, i8x64, i16x8, i16x16, i16x32, i32x4, i32x8, i32x16,
66
mask8x16, mask8x32, mask8x64, mask16x8, mask16x16, mask16x32, mask32x4, mask32x8, mask32x16,
@@ -3305,6 +3305,18 @@ impl Simd for WasmSimd128 {
33053305
(b0.simd_into(self), b1.simd_into(self))
33063306
}
33073307
}
3308+
impl SimdCvtTruncate<f32x4<WasmSimd128>> for u32x4<WasmSimd128> {
3309+
#[inline(always)]
3310+
fn truncate_from(x: f32x4<WasmSimd128>) -> Self {
3311+
u32x4_trunc_sat_f32x4(x.into()).simd_into(x.simd)
3312+
}
3313+
}
3314+
impl SimdCvtFloat<u32x4<WasmSimd128>> for f32x4<WasmSimd128> {
3315+
#[inline(always)]
3316+
fn float_from(x: u32x4<WasmSimd128>) -> Self {
3317+
f32x4_convert_u32x4(x.into()).simd_into(x.simd)
3318+
}
3319+
}
33083320
impl<S: Simd> SimdFrom<v128, S> for f32x4<S> {
33093321
#[inline(always)]
33103322
fn simd_from(arch: v128, simd: S) -> Self {

fearless_simd/src/traits.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,13 @@ impl SimdElement for u32 {
105105
impl SimdElement for i32 {
106106
type Mask = i32;
107107
}
108+
109+
/// Construction of integer vectors from floats by truncation
110+
pub trait SimdCvtTruncate<T> {
111+
fn truncate_from(x: T) -> Self;
112+
}
113+
114+
/// Construction of floating point vectors from integers
115+
pub trait SimdCvtFloat<T> {
116+
fn float_from(x: T) -> Self;
117+
}

fearless_simd_gen/src/mk_fallback.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ pub fn mk_fallback_impl() -> TokenStream {
3232

3333
quote! {
3434
use core::ops::*;
35-
use crate::{seal::Seal, Level, Simd, SimdInto};
35+
use crate::{seal::Seal, Level, Simd, SimdInto, SimdCvtTruncate, SimdCvtFloat};
3636

3737
#imports
3838

@@ -385,6 +385,26 @@ fn mk_simd_impl() -> TokenStream {
385385

386386
#( #methods )*
387387
}
388+
389+
impl SimdCvtTruncate<f32x4<#level_tok>> for u32x4<#level_tok> {
390+
#[inline(always)]
391+
fn truncate_from(x: f32x4<#level_tok>) -> Self {
392+
Self {
393+
val: x.val.map(|e| e as u32),
394+
simd: x.simd,
395+
}
396+
}
397+
}
398+
399+
impl SimdCvtFloat<u32x4<#level_tok>> for f32x4<#level_tok> {
400+
#[inline(always)]
401+
fn float_from(x: u32x4<#level_tok>) -> Self {
402+
Self {
403+
val: x.val.map(|e| e as f32),
404+
simd: x.simd,
405+
}
406+
}
407+
}
388408
}
389409
}
390410

fearless_simd_gen/src/mk_neon.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ pub fn mk_neon_impl(level: Level) -> TokenStream {
4444
quote! {
4545
use core::arch::aarch64::*;
4646

47-
use crate::{seal::Seal, Level, Simd, SimdFrom, SimdInto};
47+
use crate::{seal::Seal, Level, Simd, SimdFrom, SimdInto, SimdCvtTruncate, SimdCvtFloat};
4848

4949
#imports
5050

@@ -396,6 +396,24 @@ fn mk_simd_impl(level: Level) -> TokenStream {
396396

397397
#( #methods )*
398398
}
399+
400+
impl SimdCvtTruncate<f32x4<#level_tok>> for u32x4<#level_tok> {
401+
#[inline(always)]
402+
fn truncate_from(x: f32x4<#level_tok>) -> Self {
403+
unsafe {
404+
vcvtq_u32_f32(x.into()).simd_into(x.simd)
405+
}
406+
}
407+
}
408+
409+
impl SimdCvtFloat<u32x4<#level_tok>> for f32x4<#level_tok> {
410+
#[inline(always)]
411+
fn float_from(x: u32x4<#level_tok>) -> Self {
412+
unsafe {
413+
vcvt_f32_u32(x.into).simd_into(x.simd)
414+
}
415+
}
416+
}
399417
}
400418
}
401419

fearless_simd_gen/src/mk_simd_trait.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,17 @@ pub fn mk_simd_trait() -> TokenStream {
2626
}
2727
}
2828
let mut code = quote! {
29-
use crate::{seal::Seal, Level, SimdElement, SimdInto};
29+
use crate::{seal::Seal, Level, SimdElement, SimdInto, SimdCvtTruncate, SimdCvtFloat};
3030
#imports
3131
/// TODO: docstring
3232
// TODO: Seal
3333
pub trait Simd: Sized + Clone + Copy + Send + Sync + Seal + 'static {
34-
type f32s: SimdFloat<f32, Self, Block = f32x4<Self>>;
34+
type f32s: SimdFloat<f32, Self, Block = f32x4<Self>> + SimdCvtFloat<Self::u32s>;
3535
type u8s: SimdInt<u8, Self, Block = u8x16<Self>>;
3636
type i8s: SimdInt<i8, Self, Block = i8x16<Self>>;
3737
type u16s: SimdInt<u16, Self, Block = u16x8<Self>>;
3838
type i16s: SimdInt<i16, Self, Block = i16x8<Self>>;
39-
type u32s: SimdInt<u32, Self, Block = u32x4<Self>>;
39+
type u32s: SimdInt<u32, Self, Block = u32x4<Self>> + SimdCvtTruncate<Self::f32s>;
4040
type i32s: SimdInt<i32, Self, Block = i32x4<Self>>;
4141
type mask8s: SimdMask<i8, Self, Block = mask8x16<Self>>;
4242
type mask16s: SimdMask<i16, Self, Block = mask16x8<Self>>;
@@ -101,6 +101,9 @@ fn mk_simd_float() -> TokenStream {
101101
+ core::ops::Div<Output = Self>
102102
+ core::ops::Div<Element, Output = Self>
103103
{
104+
#[inline(always)]
105+
fn cvt_trunc<T: SimdCvtTruncate<Self>>(self) -> T { T::truncate_from(self) }
106+
104107
#( #methods )*
105108
}
106109
}
@@ -123,6 +126,9 @@ fn mk_simd_int() -> TokenStream {
123126
+ core::ops::BitXor<Output = Self>
124127
+ core::ops::BitXor<Element, Output = Self>
125128
{
129+
#[inline(always)]
130+
fn cvt_float<T: SimdCvtFloat<Self>>(self) -> T { T::float_from(self) }
131+
126132
#( #methods )*
127133
}
128134
}

fearless_simd_gen/src/mk_wasm.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,20 @@ fn mk_simd_impl(level: Level) -> TokenStream {
500500

501501
#( #methods )*
502502
}
503+
504+
impl SimdCvtTruncate<f32x4<#level_tok>> for u32x4<#level_tok> {
505+
#[inline(always)]
506+
fn truncate_from(x: f32x4<#level_tok>) -> Self {
507+
u32x4_trunc_sat_f32x4(x.into()).simd_into(x.simd)
508+
}
509+
}
510+
511+
impl SimdCvtFloat<u32x4<#level_tok>> for f32x4<#level_tok> {
512+
#[inline(always)]
513+
fn float_from(x: u32x4<#level_tok>) -> Self {
514+
f32x4_convert_u32x4(x.into()).simd_into(x.simd)
515+
}
516+
}
503517
}
504518
}
505519

@@ -512,7 +526,7 @@ pub fn mk_wasm128_impl(level: Level) -> TokenStream {
512526
quote! {
513527
use core::arch::wasm32::*;
514528

515-
use crate::{seal::Seal, Level, Simd, SimdFrom, SimdInto};
529+
use crate::{seal::Seal, Level, Simd, SimdFrom, SimdInto, SimdCvtTruncate, SimdCvtFloat};
516530

517531
#imports
518532

fearless_simd_tests/tests/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
// Copyright 2025 the Fearless_SIMD Authors
22
// SPDX-License-Identifier: Apache-2.0 OR MIT
33

4+
use fearless_simd::{Simd, SimdFloat};
5+
46
#[cfg(target_arch = "wasm32")]
57
wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
68

79
#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
810
mod wasm;
11+
12+
// Ensure that we can cast between generic native-width vectors
13+
#[allow(dead_code)]
14+
fn generic_cast<S: Simd>(x: S::f32s) -> S::u32s {
15+
x.cvt_trunc()
16+
}

0 commit comments

Comments
 (0)