Skip to content

Commit f9f9141

Browse files
committed
Introduce SimdCvt trait family
1 parent be8c910 commit f9f9141

File tree

13 files changed

+331
-26
lines changed

13 files changed

+331
-26
lines changed

fearless_simd/src/generated/fallback.rs

Lines changed: 37 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,
@@ -4847,3 +4847,39 @@ impl Simd for Fallback {
48474847
(b0.simd_into(self), b1.simd_into(self))
48484848
}
48494849
}
4850+
impl SimdCvtTruncate<f32x4<Fallback>> for i32x4<Fallback> {
4851+
#[inline(always)]
4852+
fn truncate_from(x: f32x4<Fallback>) -> Self {
4853+
Self {
4854+
val: x.val.map(|e| e as i32),
4855+
simd: x.simd,
4856+
}
4857+
}
4858+
}
4859+
impl SimdCvtTruncate<f32x4<Fallback>> for u32x4<Fallback> {
4860+
#[inline(always)]
4861+
fn truncate_from(x: f32x4<Fallback>) -> Self {
4862+
Self {
4863+
val: x.val.map(|e| e as u32),
4864+
simd: x.simd,
4865+
}
4866+
}
4867+
}
4868+
impl SimdCvtFloat<i32x4<Fallback>> for f32x4<Fallback> {
4869+
#[inline(always)]
4870+
fn float_from(x: i32x4<Fallback>) -> Self {
4871+
Self {
4872+
val: x.val.map(|e| e as f32),
4873+
simd: x.simd,
4874+
}
4875+
}
4876+
}
4877+
impl SimdCvtFloat<u32x4<Fallback>> for f32x4<Fallback> {
4878+
#[inline(always)]
4879+
fn float_from(x: u32x4<Fallback>) -> Self {
4880+
Self {
4881+
val: x.val.map(|e| e as f32),
4882+
simd: x.simd,
4883+
}
4884+
}
4885+
}

fearless_simd/src/generated/neon.rs

Lines changed: 25 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,
@@ -3138,6 +3138,30 @@ impl Simd for Neon {
31383138
(b0.simd_into(self), b1.simd_into(self))
31393139
}
31403140
}
3141+
impl SimdCvtTruncate<f32x4<Neon>> for i32x4<Neon> {
3142+
#[inline(always)]
3143+
fn truncate_from(x: f32x4<Neon>) -> Self {
3144+
unsafe { vcvtq_s32_f32(x.into()).simd_into(x.simd) }
3145+
}
3146+
}
3147+
impl SimdCvtTruncate<f32x4<Neon>> for u32x4<Neon> {
3148+
#[inline(always)]
3149+
fn truncate_from(x: f32x4<Neon>) -> Self {
3150+
unsafe { vcvtq_u32_f32(x.into()).simd_into(x.simd) }
3151+
}
3152+
}
3153+
impl SimdCvtFloat<i32x4<Neon>> for f32x4<Neon> {
3154+
#[inline(always)]
3155+
fn float_from(x: i32x4<Neon>) -> Self {
3156+
unsafe { vcvtq_f32_s32(x.into()).simd_into(x.simd) }
3157+
}
3158+
}
3159+
impl SimdCvtFloat<u32x4<Neon>> for f32x4<Neon> {
3160+
#[inline(always)]
3161+
fn float_from(x: u32x4<Neon>) -> Self {
3162+
unsafe { vcvtq_f32_u32(x.into()).simd_into(x.simd) }
3163+
}
3164+
}
31413165
impl<S: Simd> SimdFrom<float32x4_t, S> for f32x4<S> {
31423166
#[inline(always)]
31433167
fn simd_from(arch: float32x4_t, simd: S) -> Self {

fearless_simd/src/generated/simd_trait.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
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>>
12+
+ SimdCvtFloat<Self::u32s>
13+
+ SimdCvtFloat<Self::i32s>;
1214
type u8s: SimdInt<u8, Self, Block = u8x16<Self>>;
1315
type i8s: SimdInt<i8, Self, Block = i8x16<Self>>;
1416
type u16s: SimdInt<u16, Self, Block = u16x8<Self>>;
1517
type i16s: SimdInt<i16, Self, Block = i16x8<Self>>;
16-
type u32s: SimdInt<u32, Self, Block = u32x4<Self>>;
17-
type i32s: SimdInt<i32, Self, Block = i32x4<Self>>;
18+
type u32s: SimdInt<u32, Self, Block = u32x4<Self>> + SimdCvtTruncate<Self::f32s>;
19+
type i32s: SimdInt<i32, Self, Block = i32x4<Self>> + SimdCvtTruncate<Self::f32s>;
1820
type mask8s: SimdMask<i8, Self, Block = mask8x16<Self>>;
1921
type mask16s: SimdMask<i16, Self, Block = mask16x8<Self>>;
2022
type mask32s: SimdMask<i32, Self, Block = mask32x4<Self>>;
@@ -655,6 +657,10 @@ pub trait SimdFloat<Element: SimdElement, S: Simd>:
655657
+ core::ops::Div<Output = Self>
656658
+ core::ops::Div<Element, Output = Self>
657659
{
660+
#[inline(always)]
661+
fn to_int<T: SimdCvtTruncate<Self>>(self) -> T {
662+
T::truncate_from(self)
663+
}
658664
fn abs(self) -> Self;
659665
fn sqrt(self) -> Self;
660666
fn copysign(self, rhs: impl SimdInto<Self, S>) -> Self;
@@ -690,6 +696,10 @@ pub trait SimdInt<Element: SimdElement, S: Simd>:
690696
+ core::ops::BitXor<Output = Self>
691697
+ core::ops::BitXor<Element, Output = Self>
692698
{
699+
#[inline(always)]
700+
fn to_float<T: SimdCvtFloat<Self>>(self) -> T {
701+
T::float_from(self)
702+
}
693703
fn simd_eq(self, rhs: impl SimdInto<Self, S>) -> Self::Mask;
694704
fn simd_lt(self, rhs: impl SimdInto<Self, S>) -> Self::Mask;
695705
fn simd_le(self, rhs: impl SimdInto<Self, S>) -> Self::Mask;

fearless_simd/src/generated/wasm.rs

Lines changed: 25 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,
@@ -3277,6 +3277,30 @@ impl Simd for WasmSimd128 {
32773277
(b0.simd_into(self), b1.simd_into(self))
32783278
}
32793279
}
3280+
impl SimdCvtTruncate<f32x4<WasmSimd128>> for i32x4<WasmSimd128> {
3281+
#[inline(always)]
3282+
fn truncate_from(x: f32x4<WasmSimd128>) -> Self {
3283+
i32x4_trunc_sat_f32x4(x.into()).simd_into(x.simd)
3284+
}
3285+
}
3286+
impl SimdCvtTruncate<f32x4<WasmSimd128>> for u32x4<WasmSimd128> {
3287+
#[inline(always)]
3288+
fn truncate_from(x: f32x4<WasmSimd128>) -> Self {
3289+
u32x4_trunc_sat_f32x4(x.into()).simd_into(x.simd)
3290+
}
3291+
}
3292+
impl SimdCvtFloat<i32x4<WasmSimd128>> for f32x4<WasmSimd128> {
3293+
#[inline(always)]
3294+
fn float_from(x: i32x4<WasmSimd128>) -> Self {
3295+
f32x4_convert_i32x4(x.into()).simd_into(x.simd)
3296+
}
3297+
}
3298+
impl SimdCvtFloat<u32x4<WasmSimd128>> for f32x4<WasmSimd128> {
3299+
#[inline(always)]
3300+
fn float_from(x: u32x4<WasmSimd128>) -> Self {
3301+
f32x4_convert_u32x4(x.into()).simd_into(x.simd)
3302+
}
3303+
}
32803304
impl<S: Simd> SimdFrom<v128, S> for f32x4<S> {
32813305
#[inline(always)]
32823306
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: 17 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

@@ -342,6 +342,20 @@ fn mk_simd_impl() -> TokenStream {
342342
methods.push(method);
343343
}
344344
}
345+
346+
let cvts = crate::ops::conversions().map(|cvt| {
347+
let dst_scalar = cvt.dst_scalar.rust(cvt.scalar_bits);
348+
cvt.implement(
349+
&level_tok,
350+
quote! {
351+
Self {
352+
val: x.val.map(|e| e as #dst_scalar),
353+
simd: x.simd,
354+
}
355+
},
356+
)
357+
});
358+
345359
// Note: the `vectorize` implementation is pretty boilerplate and should probably
346360
// be factored out for DRY.
347361
quote! {
@@ -368,6 +382,8 @@ fn mk_simd_impl() -> TokenStream {
368382

369383
#( #methods )*
370384
}
385+
386+
#( #cvts )*
371387
}
372388
}
373389

fearless_simd_gen/src/mk_neon.rs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0 OR MIT
33

44
use proc_macro2::{Ident, Literal, Span, TokenStream};
5-
use quote::quote;
5+
use quote::{format_ident, quote};
66

77
use crate::arch::neon::split_intrinsic;
88
use crate::ops::{
@@ -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

@@ -352,6 +352,28 @@ fn mk_simd_impl(level: Level) -> TokenStream {
352352
methods.push(method);
353353
}
354354
}
355+
356+
let cvts = crate::ops::conversions().map(|cvt| {
357+
let src_prefix = scalar_prefix(cvt.src_scalar);
358+
let dst_prefix = scalar_prefix(cvt.dst_scalar);
359+
let bits = cvt.scalar_bits;
360+
let op = match cvt.len {
361+
2 => "vcvt",
362+
4 => "vcvtq",
363+
_ => unimplemented!(),
364+
};
365+
// FIXME: Saturation?
366+
let intrinsic = format_ident!("{op}_{dst_prefix}{bits}_{src_prefix}{bits}");
367+
cvt.implement(
368+
&level_tok,
369+
quote! {
370+
unsafe {
371+
#intrinsic(x.into()).simd_into(x.simd)
372+
}
373+
},
374+
)
375+
});
376+
355377
// Note: the `vectorize` implementation is pretty boilerplate and should probably
356378
// be factored out for DRY.
357379
quote! {
@@ -384,6 +406,16 @@ fn mk_simd_impl(level: Level) -> TokenStream {
384406

385407
#( #methods )*
386408
}
409+
410+
#( #cvts )*
411+
}
412+
}
413+
414+
fn scalar_prefix(ty: ScalarType) -> &'static str {
415+
match ty {
416+
ScalarType::Float => "f",
417+
ScalarType::Unsigned | ScalarType::Mask => "u",
418+
ScalarType::Int => "s",
387419
}
388420
}
389421

fearless_simd_gen/src/mk_simd_trait.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,18 @@ 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> + SimdCvtFloat<Self::i32s>;
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>>;
40-
type i32s: SimdInt<i32, Self, Block = i32x4<Self>>;
39+
type u32s: SimdInt<u32, Self, Block = u32x4<Self>> + SimdCvtTruncate<Self::f32s>;
40+
type i32s: SimdInt<i32, Self, Block = i32x4<Self>> + SimdCvtTruncate<Self::f32s>;
4141
type mask8s: SimdMask<i8, Self, Block = mask8x16<Self>>;
4242
type mask16s: SimdMask<i16, Self, Block = mask16x8<Self>>;
4343
type mask32s: SimdMask<i32, Self, Block = mask32x4<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 to_int<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 to_float<T: SimdCvtFloat<Self>>(self) -> T { T::float_from(self) }
131+
126132
#( #methods )*
127133
}
128134
}

0 commit comments

Comments
 (0)