From a9d10f7433ee64268874bbadd8ca737e284f803c Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Fri, 22 Dec 2017 13:54:54 +0100 Subject: [PATCH] Completes SSE and adds some MMX intrinsics MMX: - `_mm_cmpgt_pi{8,16,32}` - `_mm_unpack{hi,lo}_pi{8,16,32}` SSE (is now complete): - `_mm_cvtp{i,u}{8,16}_ps` - add test for `_m_pmulhuw` --- coresimd/src/x86/i586/sse.rs | 3 +- coresimd/src/x86/i686/mmx.rs | 219 ++++++++++++++++----- coresimd/src/x86/i686/sse.rs | 131 +++++++----- coresimd/src/x86/i686/sse2.rs | 23 ++- stdsimd-test/assert-instr-macro/src/lib.rs | 3 +- stdsimd-test/src/lib.rs | 7 +- stdsimd-verify/build.rs | 4 +- stdsimd-verify/src/lib.rs | 197 +++++++++--------- stdsimd-verify/tests/x86-intel.rs | 144 ++++++++------ 9 files changed, 463 insertions(+), 268 deletions(-) diff --git a/coresimd/src/x86/i586/sse.rs b/coresimd/src/x86/i586/sse.rs index 35e231d621..ee03afc9ac 100644 --- a/coresimd/src/x86/i586/sse.rs +++ b/coresimd/src/x86/i586/sse.rs @@ -3304,7 +3304,8 @@ mod tests { use v64::*; let a = mem::transmute(i8x8::new(0, 0, 0, 0, 0, 0, 0, 7)); - let mut mem = ::std::boxed::Box::<__m64>::new(mem::transmute(i8x8::splat(1))); + let mut mem = + ::std::boxed::Box::<__m64>::new(mem::transmute(i8x8::splat(1))); sse::_mm_stream_pi(&mut *mem as *mut _ as *mut _, a); assert_eq!(a, *mem); } diff --git a/coresimd/src/x86/i686/mmx.rs b/coresimd/src/x86/i686/mmx.rs index 476ad957e6..c7e34f492e 100644 --- a/coresimd/src/x86/i686/mmx.rs +++ b/coresimd/src/x86/i686/mmx.rs @@ -16,7 +16,7 @@ use stdsimd_test::assert_instr; /// Constructs a 64-bit integer vector initialized to zero. #[inline(always)] -#[target_feature = "+mmx,+sse"] +#[target_feature = "+mmx"] // FIXME: this produces a movl instead of xorps on x86 // FIXME: this produces a xor intrinsic instead of xorps on x86_64 #[cfg_attr(all(test, target_arch = "x86_64"), assert_instr(xor))] @@ -30,7 +30,7 @@ pub unsafe fn _mm_setzero_si64() -> __m64 { /// Positive values greater than 0x7F are saturated to 0x7F. Negative values /// less than 0x80 are saturated to 0x80. #[inline(always)] -#[target_feature = "+mmx,+sse"] +#[target_feature = "+mmx"] #[cfg_attr(test, assert_instr(packsswb))] pub unsafe fn _mm_packs_pi16(a: i16x4, b: i16x4) -> i8x8 { mem::transmute(packsswb(mem::transmute(a), mem::transmute(b))) @@ -42,17 +42,14 @@ pub unsafe fn _mm_packs_pi16(a: i16x4, b: i16x4) -> i8x8 { /// Positive values greater than 0x7F are saturated to 0x7F. Negative values /// less than 0x80 are saturated to 0x80. #[inline(always)] -#[target_feature = "+mmx,+sse"] +#[target_feature = "+mmx"] #[cfg_attr(test, assert_instr(packssdw))] pub unsafe fn _mm_packs_pi32(a: i32x2, b: i32x2) -> i16x4 { mem::transmute(packssdw(mem::transmute(a), mem::transmute(b))) } -/// Compares the 8-bit integer elements of two 64-bit integer vectors of -/// [8 x i8] to determine if the element of the first vector is greater than -/// the corresponding element of the second vector. -/// -/// The comparison yields 0 for false, 0xFF for true. +/// Compares whether each element of `a` is greater than the corresponding +/// element of `b` returning `0` for `false` and `-1` for `true`. #[inline(always)] #[target_feature = "+mmx"] #[cfg_attr(test, assert_instr(pcmpgtb))] @@ -60,11 +57,8 @@ pub unsafe fn _mm_cmpgt_pi8(a: i8x8, b: i8x8) -> i8x8 { mem::transmute(pcmpgtb(mem::transmute(a), mem::transmute(b))) } -/// Compares the 16-bit integer elements of two 64-bit integer vectors of -/// [4 x i16] to determine if the element of the first vector is greater than -/// the corresponding element of the second vector. -/// -/// The comparison yields 0 for false, 0xFFFF for true. +/// Compares whether each element of `a` is greater than the corresponding +/// element of `b` returning `0` for `false` and `-1` for `true`. #[inline(always)] #[target_feature = "+mmx"] #[cfg_attr(test, assert_instr(pcmpgtw))] @@ -72,17 +66,35 @@ pub unsafe fn _mm_cmpgt_pi16(a: i16x4, b: i16x4) -> i16x4 { mem::transmute(pcmpgtw(mem::transmute(a), mem::transmute(b))) } -/// Unpacks the upper 32 bits from two 64-bit integer vectors of -/// [4 x i16] and interleaves them into a 64-bit integer vector of [4 x i16]. +/// Unpacks the upper two elements from two `i16x4` vectors and interleaves +/// them into the result: `[a.2, b.2, a.3, b.3]`. #[inline(always)] #[target_feature = "+mmx"] -#[cfg_attr(test, assert_instr(punpckhwd))] // FIXME punpcklbw expected +#[cfg_attr(test, assert_instr(punpcklbw))] // TODO: check pub unsafe fn _mm_unpackhi_pi16(a: i16x4, b: i16x4) -> i16x4 { - mem::transmute(punpckhwd(mem::transmute(a), mem::transmute(b))) + mem::transmute(punpcklbw(mem::transmute(a), mem::transmute(b))) +} + +/// Compares whether each element of `a` is greater than the corresponding +/// element of `b` returning `0` for `false` and `-1` for `true`. +#[inline(always)] +#[target_feature = "+mmx"] +#[cfg_attr(test, assert_instr(pcmpgtd))] +pub unsafe fn _mm_cmpgt_pi32(a: i32x2, b: i32x2) -> i32x2 { + mem::transmute(pcmpgtd(mem::transmute(a), mem::transmute(b))) +} + +/// Unpacks the upper four elements from two `i8x8` vectors and interleaves +/// them into the result: `[a.4, b.4, a.5, b.5, a.6, b.6, a.7, b.7]`. +#[inline(always)] +#[target_feature = "+mmx"] +#[cfg_attr(test, assert_instr(punpckhbw))] +pub unsafe fn _mm_unpackhi_pi8(a: i8x8, b: i8x8) -> i8x8 { + mem::transmute(punpckhbw(mem::transmute(a), mem::transmute(b))) } -/// Unpacks the lower 32 bits from two 64-bit integer vectors of [8 x i8] -/// and interleaves them into a 64-bit integer vector of [8 x i8]. +/// Unpacks the lower four elements from two `i8x8` vectors and interleaves +/// them into the result: `[a.0, b.0, a.1, b.1, a.2, b.2, a.3, b.3]`. #[inline(always)] #[target_feature = "+mmx"] #[cfg_attr(test, assert_instr(punpcklbw))] @@ -90,8 +102,8 @@ pub unsafe fn _mm_unpacklo_pi8(a: i8x8, b: i8x8) -> i8x8 { mem::transmute(punpcklbw(mem::transmute(a), mem::transmute(b))) } -/// Unpacks the lower 32 bits from two 64-bit integer vectors of -/// [4 x i16] and interleaves them into a 64-bit integer vector of [4 x i16]. +/// Unpacks the lower two elements from two `i16x4` vectors and interleaves +/// them into the result: `[a.0 b.0 a.1 b.1]`. #[inline(always)] #[target_feature = "+mmx"] #[cfg_attr(test, assert_instr(punpcklwd))] @@ -99,6 +111,24 @@ pub unsafe fn _mm_unpacklo_pi16(a: i16x4, b: i16x4) -> i16x4 { mem::transmute(punpcklwd(mem::transmute(a), mem::transmute(b))) } +/// Unpacks the upper element from two `i32x2` vectors and interleaves them +/// into the result: `[a.1, b.1]`. +#[inline(always)] +#[target_feature = "+mmx"] +#[cfg_attr(test, assert_instr(punpckhdq))] +pub unsafe fn _mm_unpackhi_pi32(a: i32x2, b: i32x2) -> i32x2 { + mem::transmute(punpckhdq(mem::transmute(a), mem::transmute(b))) +} + +/// Unpacks the lower element from two `i32x2` vectors and interleaves them +/// into the result: `[a.0, b.0]`. +#[inline(always)] +#[target_feature = "+mmx"] +#[cfg_attr(test, assert_instr(punpckldq))] +pub unsafe fn _mm_unpacklo_pi32(a: i32x2, b: i32x2) -> i32x2 { + mem::transmute(punpckldq(mem::transmute(a), mem::transmute(b))) +} + #[allow(improper_ctypes)] extern "C" { #[link_name = "llvm.x86.mmx.packsswb"] @@ -109,12 +139,20 @@ extern "C" { fn pcmpgtb(a: __m64, b: __m64) -> __m64; #[link_name = "llvm.x86.mmx.pcmpgt.w"] fn pcmpgtw(a: __m64, b: __m64) -> __m64; + #[link_name = "llvm.x86.mmx.pcmpgt.d"] + fn pcmpgtd(a: __m64, b: __m64) -> __m64; #[link_name = "llvm.x86.mmx.punpckhwd"] fn punpckhwd(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.punpcklbw"] - fn punpcklbw(a: __m64, b: __m64) -> __m64; #[link_name = "llvm.x86.mmx.punpcklwd"] fn punpcklwd(a: __m64, b: __m64) -> __m64; + #[link_name = "llvm.x86.mmx.punpckhbw"] + fn punpckhbw(a: __m64, b: __m64) -> __m64; + #[link_name = "llvm.x86.mmx.punpcklbw"] + fn punpcklbw(a: __m64, b: __m64) -> __m64; + #[link_name = "llvm.x86.mmx.punpckhdq"] + fn punpckhdq(a: __m64, b: __m64) -> __m64; + #[link_name = "llvm.x86.mmx.punpckldq"] + fn punpckldq(a: __m64, b: __m64) -> __m64; } #[cfg(test)] @@ -123,13 +161,13 @@ mod tests { use x86::i686::mmx; use stdsimd_test::simd_test; - #[simd_test = "sse"] // FIXME: should be mmx + #[simd_test = "mmx"] unsafe fn _mm_setzero_si64() { let r: __m64 = ::std::mem::transmute(0_i64); assert_eq!(r, mmx::_mm_setzero_si64()); } - #[simd_test = "sse"] // FIXME: should be mmx + #[simd_test = "mmx"] unsafe fn _mm_packs_pi16() { let a = i16x4::new(-1, 2, -3, 4); let b = i16x4::new(-5, 6, -7, 8); @@ -137,7 +175,7 @@ mod tests { assert_eq!(r, mmx::_mm_packs_pi16(a, b)); } - #[simd_test = "sse"] // FIXME: should be mmx + #[simd_test = "mmx"] unsafe fn _mm_packs_pi32() { let a = i32x2::new(-1, 2); let b = i32x2::new(-5, 6); @@ -147,41 +185,128 @@ mod tests { #[simd_test = "mmx"] unsafe fn _mm_cmpgt_pi8() { - let a = i8x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let b = i8x8::new(8, 7, 6, 5, 4, 3, 2, 1); - let r = i8x8::new(0, 0, 0, 0, 0, -1, -1, -1); - assert_eq!(r, mmx::_mm_cmpgt_pi8(a, b)); + { + let a = i8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let b = i8x8::new(8, 7, 6, 5, 4, 3, 2, 1); + let r = i8x8::new(0, 0, 0, 0, 0, -1, -1, -1); + assert_eq!(r, mmx::_mm_cmpgt_pi8(a, b)); + } + { + let a = i8x8::new(0, 3, 4, 7, 8, 11, 12, 15); + let b = i8x8::new(1, 2, 5, 6, 9, 10, 13, 14); + let r0 = i8x8::new(0, -1, 0, -1, 0, -1, 0, -1); + let r1 = i8x8::new(-1, 0, -1, 0, -1, 0, -1, 0); + + assert_eq!(r0, mmx::_mm_cmpgt_pi8(a, b)); + assert_eq!(r1, mmx::_mm_cmpgt_pi8(b, a)); + } } #[simd_test = "mmx"] unsafe fn _mm_cmpgt_pi16() { - let a = i16x4::new(0, 1, 2, 3); - let b = i16x4::new(4, 3, 2, 1); - let r = i16x4::new(0, 0, 0, -1); - assert_eq!(r, mmx::_mm_cmpgt_pi16(a, b)); + { + let a = i16x4::new(0, 1, 2, 3); + let b = i16x4::new(4, 3, 2, 1); + let r = i16x4::new(0, 0, 0, -1); + assert_eq!(r, mmx::_mm_cmpgt_pi16(a, b)); + } + { + let a = i16x4::new(0, 3, 4, 7); + let b = i16x4::new(1, 2, 5, 6); + let r0 = i16x4::new(0, -1, 0, -1); + let r1 = i16x4::new(-1, 0, -1, 0); + + assert_eq!(r0, mmx::_mm_cmpgt_pi16(a, b)); + assert_eq!(r1, mmx::_mm_cmpgt_pi16(b, a)); + } } #[simd_test = "mmx"] - unsafe fn _mm_unpackhi_pi16() { - let a = i16x4::new(0, 1, 2, 3); - let b = i16x4::new(4, 5, 6, 7); - let r = i16x4::new(2, 6, 3, 7); - assert_eq!(r, mmx::_mm_unpackhi_pi16(a, b)); + unsafe fn _mm_cmpgt_pi32() { + let a = i32x2::new(0, 3); + let b = i32x2::new(1, 2); + let r0 = i32x2::new(0, -1); + let r1 = i32x2::new(-1, 0); + + assert_eq!(r0, mmx::_mm_cmpgt_pi32(a, b)); + assert_eq!(r1, mmx::_mm_cmpgt_pi32(b, a)); + } + + #[simd_test = "mmx"] + unsafe fn _mm_unpackhi_pi8() { + let a = i8x8::new(0, 3, 4, 7, 8, 11, 12, 15); + let b = i8x8::new(1, 2, 5, 6, 9, 10, 13, 14); + let r = i8x8::new(8, 9, 11, 10, 12, 13, 15, 14); + + assert_eq!(r, mmx::_mm_unpackhi_pi8(a, b)); } #[simd_test = "mmx"] unsafe fn _mm_unpacklo_pi8() { - let a = i8x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let b = i8x8::new(8, 9, 10, 11, 12, 13, 14, 15); - let r = i8x8::new(0, 8, 1, 9, 2, 10, 3, 11); - assert_eq!(r, mmx::_mm_unpacklo_pi8(a, b)); + { + let a = i8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let b = i8x8::new(8, 9, 10, 11, 12, 13, 14, 15); + let r = i8x8::new(0, 8, 1, 9, 2, 10, 3, 11); + assert_eq!(r, mmx::_mm_unpacklo_pi8(a, b)); + } + { + let a = i8x8::new(0, 3, 4, 7, 8, 11, 12, 15); + let b = i8x8::new(1, 2, 5, 6, 9, 10, 13, 14); + let r = i8x8::new(0, 1, 3, 2, 4, 5, 7, 6); + assert_eq!(r, mmx::_mm_unpacklo_pi8(a, b)); + } + } + + #[simd_test = "mmx"] + unsafe fn _mm_unpackhi_pi16() { + { + let a = i16x4::new(0, 1, 2, 3); + let b = i16x4::new(4, 5, 6, 7); + let r = i16x4::new(2, 6, 3, 7); + assert_eq!(r, mmx::_mm_unpackhi_pi16(a, b)); + } + { + let a = i16x4::new(0, 3, 4, 7); + let b = i16x4::new(1, 2, 5, 6); + let r = i16x4::new(4, 5, 7, 6); + + assert_eq!(r, mmx::_mm_unpackhi_pi16(a, b)); + } } #[simd_test = "mmx"] unsafe fn _mm_unpacklo_pi16() { - let a = i16x4::new(0, 1, 2, 3); - let b = i16x4::new(4, 5, 6, 7); - let r = i16x4::new(0, 4, 1, 5); - assert_eq!(r, mmx::_mm_unpacklo_pi16(a, b)); + { + let a = i16x4::new(0, 1, 2, 3); + let b = i16x4::new(4, 5, 6, 7); + let r = i16x4::new(0, 4, 1, 5); + assert_eq!(r, mmx::_mm_unpacklo_pi16(a, b)); + } + { + let a = i16x4::new(0, 3, 4, 7); + let b = i16x4::new(1, 2, 5, 6); + let r = i16x4::new(0, 1, 3, 2); + + assert_eq!(r, mmx::_mm_unpacklo_pi16(a, b)); + } } + + #[simd_test = "mmx"] + unsafe fn _mm_unpackhi_pi32() { + let a = i32x2::new(0, 3); + let b = i32x2::new(1, 2); + let r = i32x2::new(3, 2); + + assert_eq!(r, mmx::_mm_unpackhi_pi32(a, b)); + } + + #[simd_test = "mmx"] + unsafe fn _mm_unpacklo_pi32() { + let a = i32x2::new(0, 3); + let b = i32x2::new(1, 2); + let r = i32x2::new(0, 1); + + assert_eq!(r, mmx::_mm_unpacklo_pi32(a, b)); + } + } diff --git a/coresimd/src/x86/i686/sse.rs b/coresimd/src/x86/i686/sse.rs index 92e3e110bc..9d19db0dfa 100644 --- a/coresimd/src/x86/i686/sse.rs +++ b/coresimd/src/x86/i686/sse.rs @@ -221,54 +221,48 @@ pub unsafe fn _mm_cvt_pi2ps(a: f32x4, b: i32x2) -> f32x4 { _mm_cvtpi32_ps(a, b) } -/// Converts a 64-bit vector of [4 x i16] into a 128-bit vector of [4 x -/// float]. +/// Converts the lower 4 values of `a` into a 128-bit vector of 4 `f32`s. #[inline(always)] #[target_feature = "+sse"] -pub unsafe fn _mm_cvtpi16_ps(a: i16x4) -> f32x4 { - let b = mmx::_mm_setzero_si64(); - let b = mmx::_mm_cmpgt_pi16(mem::transmute(b), a); - let c = mmx::_mm_unpackhi_pi16(a, b); - let r = i586::_mm_setzero_ps(); - let r = cvtpi2ps(r, mem::transmute(c)); - let r = i586::_mm_movelh_ps(r, r); - let c = mmx::_mm_unpacklo_pi16(a, b); - cvtpi2ps(r, mem::transmute(c)) +#[cfg_attr(test, assert_instr(cvtpi2ps))] +pub unsafe fn _mm_cvtpi8_ps(a: i8x8) -> f32x4 { + let b = mmx::_mm_cmpgt_pi8(mem::transmute(mmx::_mm_setzero_si64()), a); + _mm_cvtpi16_ps(mem::transmute(mmx::_mm_unpacklo_pi8(a, b))) } -/// Converts a 64-bit vector of 16-bit unsigned integer values into a -/// 128-bit vector of [4 x float]. +/// Converts the lower 4 values of `a` into a 128-bit vector of 4 `f32`s. #[inline(always)] #[target_feature = "+sse"] -pub unsafe fn _mm_cvtpu16_ps(a: u16x4) -> f32x4 { +#[cfg_attr(test, assert_instr(cvtpi2ps))] +pub unsafe fn _mm_cvtpu8_ps(a: u8x8) -> f32x4 { let b = mem::transmute(mmx::_mm_setzero_si64()); - let c = mmx::_mm_unpackhi_pi16(a.as_i16x4(), b); - let r = i586::_mm_setzero_ps(); - let r = cvtpi2ps(r, mem::transmute(c)); - let r = i586::_mm_movelh_ps(r, r); - let c = mmx::_mm_unpacklo_pi16(a.as_i16x4(), b); - cvtpi2ps(r, mem::transmute(c)) + _mm_cvtpi16_ps(mem::transmute(mmx::_mm_unpacklo_pi8(mem::transmute(a), b))) } -/// Converts the lower four 8-bit values from a 64-bit vector of [8 x i8] -/// into a 128-bit vector of [4 x float]. +/// Converts a 64-bit vector of `i16`s into a 128-bit vector of 4 `f32`s. #[inline(always)] #[target_feature = "+sse"] -pub unsafe fn _mm_cvtpi8_ps(a: i8x8) -> f32x4 { - let b = mmx::_mm_setzero_si64(); - let b = mmx::_mm_cmpgt_pi8(mem::transmute(b), a); - let b = mmx::_mm_unpacklo_pi8(a, b); - _mm_cvtpi16_ps(mem::transmute(b)) +#[cfg_attr(test, assert_instr(cvtpi2ps))] +pub unsafe fn _mm_cvtpi16_ps(a: i16x4) -> f32x4 { + let b = mmx::_mm_cmpgt_pi16(mem::transmute(mmx::_mm_setzero_si64()), a); + let c = mmx::_mm_unpackhi_pi16(a, b); + let d = _mm_cvtpi32_ps(i586::_mm_setzero_ps(), mem::transmute(c)); + let d = i586::_mm_movelh_ps(d, d); + let e = mmx::_mm_unpacklo_pi16(a, b); + _mm_cvtpi32_ps(d, mem::transmute(e)) } -/// Converts the lower four unsigned 8-bit integer values from a 64-bit -/// vector of [8 x u8] into a 128-bit vector of [4 x float]. +/// Converts a 64-bit vector of 4 `u16`s into a 128-bit vector of 4 `f32`s. #[inline(always)] #[target_feature = "+sse"] -pub unsafe fn _mm_cvtpu8_ps(a: u8x8) -> f32x4 { - let b = mmx::_mm_setzero_si64(); - let b = mmx::_mm_unpacklo_pi8(a.as_i8x8(), mem::transmute(b)); - _mm_cvtpi16_ps(mem::transmute(b)) +#[cfg_attr(test, assert_instr(cvtpi2ps))] +pub unsafe fn _mm_cvtpu16_ps(a: u16x4) -> f32x4 { + let b = mem::transmute(mmx::_mm_setzero_si64()); + let c = mmx::_mm_unpackhi_pi16(mem::transmute(a), b); + let d = _mm_cvtpi32_ps(i586::_mm_setzero_ps(), mem::transmute(c)); + let d = i586::_mm_movelh_ps(d, d); + let c = mmx::_mm_unpacklo_pi16(mem::transmute(a), b); + _mm_cvtpi32_ps(d, mem::transmute(c)) } /// Converts the two 32-bit signed integer values from each 64-bit vector @@ -513,6 +507,13 @@ mod tests { assert_eq!(r, u16x4::splat(15)); } + #[simd_test = "sse"] + unsafe fn _m_pmulhuw() { + let (a, b) = (u16x4::splat(1000), u16x4::splat(1001)); + let r = sse::_m_pmulhuw(a, b); + assert_eq!(r, u16x4::splat(15)); + } + #[simd_test = "sse"] unsafe fn _mm_avg_pu8() { let (a, b) = (u8x8::splat(3), u8x8::splat(9)); @@ -559,34 +560,66 @@ mod tests { #[simd_test = "sse"] unsafe fn _mm_cvtpi16_ps() { - let a = i16x4::new(1, 2, 3, 4); - let expected = f32x4::new(1., 2., 3., 4.); - let r = sse::_mm_cvtpi16_ps(a); - assert_eq!(r, expected); + { + let a = i16x4::new(-2, 3, -4, 5); + let e = f32x4::new(-2.0, 3.0, -4.0, 5.0); + let r = sse::_mm_cvtpi16_ps(a); + assert_eq!(r, e); + } + { + let a = i16x4::new(1, 2, 3, 4); + let expected = f32x4::new(1., 2., 3., 4.); + let r = sse::_mm_cvtpi16_ps(a); + assert_eq!(r, expected); + } } #[simd_test = "sse"] unsafe fn _mm_cvtpu16_ps() { - let a = u16x4::new(1, 2, 3, 4); - let expected = f32x4::new(1., 2., 3., 4.); - let r = sse::_mm_cvtpu16_ps(a); - assert_eq!(r, expected); + { + let a = u16x4::new(2, 3, 4, 5); + let e = f32x4::new(2.0, 3.0, 4.0, 5.0); + let r = sse::_mm_cvtpu16_ps(a); + assert_eq!(r, e); + } + { + let a = u16x4::new(1, 2, 3, 4); + let expected = f32x4::new(1., 2., 3., 4.); + let r = sse::_mm_cvtpu16_ps(a); + assert_eq!(r, expected); + } } #[simd_test = "sse"] unsafe fn _mm_cvtpi8_ps() { - let a = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let expected = f32x4::new(1., 2., 3., 4.); - let r = sse::_mm_cvtpi8_ps(a); - assert_eq!(r, expected); + { + let a = i8x8::new(-2, 3, -4, 5, 1, 1, 1, 1); + let e = f32x4::new(-2.0, 3.0, -4.0, 5.0); + let r = sse::_mm_cvtpi8_ps(a); + assert_eq!(r, e); + } + { + let a = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let expected = f32x4::new(1., 2., 3., 4.); + let r = sse::_mm_cvtpi8_ps(a); + assert_eq!(r, expected); + } } #[simd_test = "sse"] unsafe fn _mm_cvtpu8_ps() { - let a = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let expected = f32x4::new(1., 2., 3., 4.); - let r = sse::_mm_cvtpu8_ps(a); - assert_eq!(r, expected); + { + let a = u8x8::new(2, 3, 4, 5, 1, 1, 1, 1); + let e = f32x4::new(2.0, 3.0, 4.0, 5.0); + let r = sse::_mm_cvtpu8_ps(a); + assert_eq!(r, e); + } + { + let a = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let expected = f32x4::new(1., 2., 3., 4.); + let r = sse::_mm_cvtpu8_ps(a); + assert_eq!(r, expected); + } } #[simd_test = "sse"] diff --git a/coresimd/src/x86/i686/sse2.rs b/coresimd/src/x86/i686/sse2.rs index c1c07f9524..2b4e5957ef 100644 --- a/coresimd/src/x86/i686/sse2.rs +++ b/coresimd/src/x86/i686/sse2.rs @@ -76,7 +76,8 @@ pub unsafe fn _mm_setr_epi64(e1: __m64, e0: __m64) -> i64x2 { /// integer. #[inline(always)] #[target_feature = "+sse2"] -// #[cfg_attr(test, assert_instr(movdq2q))] // FIXME: llvm codegens wrong instr? +// #[cfg_attr(test, assert_instr(movdq2q))] // FIXME: llvm codegens wrong +// instr? pub unsafe fn _mm_movepi64_pi64(a: i64x2) -> __m64 { mem::transmute(a.extract(0)) } @@ -85,7 +86,8 @@ pub unsafe fn _mm_movepi64_pi64(a: i64x2) -> __m64 { /// upper bits. #[inline(always)] #[target_feature = "+sse2"] -// #[cfg_attr(test, assert_instr(movq2dq))] // FIXME: llvm codegens wrong instr? +// #[cfg_attr(test, assert_instr(movq2dq))] // FIXME: llvm codegens wrong +// instr? pub unsafe fn _mm_movpi64_epi64(a: __m64) -> i64x2 { i64x2::new(mem::transmute(a), 0) } @@ -178,7 +180,8 @@ mod tests { #[simd_test = "sse2"] unsafe fn _mm_set_epi64() { - let r = sse2::_mm_set_epi64(mem::transmute(1i64), mem::transmute(2i64)); + let r = + sse2::_mm_set_epi64(mem::transmute(1i64), mem::transmute(2i64)); assert_eq!(r, i64x2::new(2, 1)); } @@ -190,7 +193,8 @@ mod tests { #[simd_test = "sse2"] unsafe fn _mm_setr_epi64() { - let r = sse2::_mm_setr_epi64(mem::transmute(1i64), mem::transmute(2i64)); + let r = + sse2::_mm_setr_epi64(mem::transmute(1i64), mem::transmute(2i64)); assert_eq!(r, i64x2::new(1, 2)); } @@ -202,7 +206,16 @@ mod tests { #[simd_test = "sse2"] unsafe fn _mm_movpi64_epi64() { - let r = sse2::_mm_movpi64_epi64(mem::transmute(i8x8::new(5, 0, 0, 0, 0, 0, 0, 0))); + let r = sse2::_mm_movpi64_epi64(mem::transmute(i8x8::new( + 5, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ))); assert_eq!(r, i64x2::new(5, 0)); } diff --git a/stdsimd-test/assert-instr-macro/src/lib.rs b/stdsimd-test/assert-instr-macro/src/lib.rs index 38a42c4ec9..4d347f89d9 100644 --- a/stdsimd-test/assert-instr-macro/src/lib.rs +++ b/stdsimd-test/assert-instr-macro/src/lib.rs @@ -42,8 +42,7 @@ pub fn assert_instr( let assert_name = syn::Ident::from( &format!("assert_{}_{}", name.as_ref(), instr.as_ref())[..], ); - let shim_name = - syn::Ident::from(format!("{}_shim", name.as_ref())); + let shim_name = syn::Ident::from(format!("{}_shim", name.as_ref())); let (to_test, test_name) = if invoc.args.len() == 0 { (TokenStream::empty(), &func.ident) } else { diff --git a/stdsimd-test/src/lib.rs b/stdsimd-test/src/lib.rs index 9e03eb5a67..b790fd3734 100644 --- a/stdsimd-test/src/lib.rs +++ b/stdsimd-test/src/lib.rs @@ -293,7 +293,9 @@ pub fn assert(fnptr: usize, fnname: &str, expected: &str) { } } - let probably_only_one_instruction = function.instrs.len() < 30; + let instruction_limit = 30; + let probably_only_one_instruction = + function.instrs.len() < instruction_limit; if found && probably_only_one_instruction { return; @@ -319,7 +321,8 @@ pub fn assert(fnptr: usize, fnname: &str, expected: &str) { expected ); } else if !probably_only_one_instruction { - panic!("too many instructions in the disassembly"); + panic!("instruction found, but the disassembly contains too many instructions: #instructions = {} !< {} (limit)", + function.instrs.len(), instruction_limit); } } diff --git a/stdsimd-verify/build.rs b/stdsimd-verify/build.rs index 3273777679..28554bac42 100644 --- a/stdsimd-verify/build.rs +++ b/stdsimd-verify/build.rs @@ -12,11 +12,11 @@ fn walk(root: &Path) { let file = file.unwrap(); if file.file_type().unwrap().is_dir() { walk(&file.path()); - continue + continue; } let path = file.path(); if path.extension().and_then(|s| s.to_str()) != Some("rs") { - continue + continue; } println!("cargo:rerun-if-changed={}", path.display()); diff --git a/stdsimd-verify/src/lib.rs b/stdsimd-verify/src/lib.rs index 5660cd05e9..b00398a001 100644 --- a/stdsimd-verify/src/lib.rs +++ b/stdsimd-verify/src/lib.rs @@ -1,10 +1,10 @@ #![feature(proc_macro)] -extern crate proc_macro; extern crate proc_macro2; -extern crate syn; +extern crate proc_macro; #[macro_use] extern crate quote; +extern crate syn; use std::path::Path; use std::fs::File; @@ -42,21 +42,21 @@ pub fn x86_functions(input: TokenStream) -> TokenStream { _ => return false, } if f.unsafety.is_none() { - return false + return false; } - f.attrs.iter() + f.attrs + .iter() .filter_map(|a| a.meta_item()) - .any(|a| { - match a { - syn::MetaItem::NameValue(i) => i.ident == "target_feature", - _ => false, - } + .any(|a| match a { + syn::MetaItem::NameValue(i) => i.ident == "target_feature", + _ => false, }) }); let input = proc_macro2::TokenStream::from(input); - let functions = functions.iter() + let functions = functions + .iter() .map(|f| { let name = f.ident; // println!("{}", name); @@ -96,53 +96,51 @@ pub fn x86_functions(input: TokenStream) -> TokenStream { fn to_type(t: &syn::Type) -> Tokens { match *t { - syn::Type::Path(ref p) => { - match extract_path_ident(&p.path).as_ref() { - "__m128i" => my_quote! { &I8x16 }, - "__m256i" => my_quote! { &I8x32 }, - "__m64" => my_quote! { &I8x8 }, - "bool" => my_quote! { &BOOL }, - "f32" => my_quote! { &F32 }, - "f32x4" => my_quote! { &F32x4 }, - "f32x8" => my_quote! { &F32x8 }, - "f64" => my_quote! { &F64 }, - "f64x2" => my_quote! { &F64x2 }, - "f64x4" => my_quote! { &F64x4 }, - "i16" => my_quote! { &I16 }, - "i16x16" => my_quote! { &I16x16 }, - "i16x4" => my_quote! { &I16x4 }, - "i16x8" => my_quote! { &I16x8 }, - "i32" => my_quote! { &I32 }, - "i32x2" => my_quote! { &I32x2 }, - "i32x4" => my_quote! { &I32x4 }, - "i32x8" => my_quote! { &I32x8 }, - "i64" => my_quote! { &I64 }, - "i64x2" => my_quote! { &I64x2 }, - "i64x4" => my_quote! { &I64x4 }, - "i8" => my_quote! { &I8 }, - "i8x16" => my_quote! { &I8x16 }, - "i8x32" => my_quote! { &I8x32 }, - "i8x8" => my_quote! { &I8x8 }, - "u16x4" => my_quote! { &U16x4 }, - "u16x8" => my_quote! { &U16x8 }, - "u32" => my_quote! { &U32 }, - "u32x2" => my_quote! { &U32x2 }, - "u32x4" => my_quote! { &U32x4 }, - "u32x8" => my_quote! { &U32x8 }, - "u64" => my_quote! { &U64 }, - "u64x2" => my_quote! { &U64x2 }, - "u64x4" => my_quote! { &U64x4 }, - "u8" => my_quote! { &U8 }, - "u16" => my_quote! { &U16 }, - "u8x16" => my_quote! { &U8x16 }, - "u8x32" => my_quote! { &U8x32 }, - "u16x16" => my_quote! { &U16x16 }, - "u8x8" => my_quote! { &U8x8 }, - s => panic!("unspported type: {}", s), - } - } - syn::Type::Ptr(syn::TypePtr { ref elem, .. }) | - syn::Type::Reference(syn::TypeReference { ref elem, .. }) => { + syn::Type::Path(ref p) => match extract_path_ident(&p.path).as_ref() { + "__m128i" => my_quote! { &I8x16 }, + "__m256i" => my_quote! { &I8x32 }, + "__m64" => my_quote! { &I8x8 }, + "bool" => my_quote! { &BOOL }, + "f32" => my_quote! { &F32 }, + "f32x4" => my_quote! { &F32x4 }, + "f32x8" => my_quote! { &F32x8 }, + "f64" => my_quote! { &F64 }, + "f64x2" => my_quote! { &F64x2 }, + "f64x4" => my_quote! { &F64x4 }, + "i16" => my_quote! { &I16 }, + "i16x16" => my_quote! { &I16x16 }, + "i16x4" => my_quote! { &I16x4 }, + "i16x8" => my_quote! { &I16x8 }, + "i32" => my_quote! { &I32 }, + "i32x2" => my_quote! { &I32x2 }, + "i32x4" => my_quote! { &I32x4 }, + "i32x8" => my_quote! { &I32x8 }, + "i64" => my_quote! { &I64 }, + "i64x2" => my_quote! { &I64x2 }, + "i64x4" => my_quote! { &I64x4 }, + "i8" => my_quote! { &I8 }, + "i8x16" => my_quote! { &I8x16 }, + "i8x32" => my_quote! { &I8x32 }, + "i8x8" => my_quote! { &I8x8 }, + "u16x4" => my_quote! { &U16x4 }, + "u16x8" => my_quote! { &U16x8 }, + "u32" => my_quote! { &U32 }, + "u32x2" => my_quote! { &U32x2 }, + "u32x4" => my_quote! { &U32x4 }, + "u32x8" => my_quote! { &U32x8 }, + "u64" => my_quote! { &U64 }, + "u64x2" => my_quote! { &U64x2 }, + "u64x4" => my_quote! { &U64x4 }, + "u8" => my_quote! { &U8 }, + "u16" => my_quote! { &U16 }, + "u8x16" => my_quote! { &U8x16 }, + "u8x32" => my_quote! { &U8x32 }, + "u16x16" => my_quote! { &U16x16 }, + "u8x8" => my_quote! { &U8x8 }, + s => panic!("unspported type: {}", s), + }, + syn::Type::Ptr(syn::TypePtr { ref elem, .. }) + | syn::Type::Reference(syn::TypeReference { ref elem, .. }) => { let tokens = to_type(&elem); my_quote! { &Type::Ptr(#tokens) } } @@ -162,7 +160,7 @@ fn extract_path_ident(path: &syn::Path) -> syn::Ident { } match path.segments.first().unwrap().item().arguments { syn::PathArguments::None => {} - _ => panic!("unsupported path that has path arguments") + _ => panic!("unsupported path that has path arguments"), } path.segments.first().unwrap().item().ident } @@ -172,71 +170,72 @@ fn walk(root: &Path, files: &mut Vec) { let file = file.unwrap(); if file.file_type().unwrap().is_dir() { walk(&file.path(), files); - continue + continue; } let path = file.path(); if path.extension().and_then(|s| s.to_str()) != Some("rs") { - continue + continue; } let mut contents = String::new(); - File::open(&path).unwrap().read_to_string(&mut contents).unwrap(); - - files.push(syn::parse_str::(&contents).expect("failed to parse")); + File::open(&path) + .unwrap() + .read_to_string(&mut contents) + .unwrap(); + + files.push( + syn::parse_str::(&contents).expect("failed to parse"), + ); } } fn find_instrs(attrs: &[syn::Attribute]) -> Vec { - attrs.iter() + attrs + .iter() .filter_map(|a| a.meta_item()) - .filter_map(|a| { - match a { - syn::MetaItem::List(i) => { - if i.ident == "cfg_attr" { - i.nested.into_iter().next() - } else { - None - } + .filter_map(|a| match a { + syn::MetaItem::List(i) => { + if i.ident == "cfg_attr" { + i.nested.into_iter().next() + } else { + None } - _ => None, } + _ => None, }) - .filter_map(|nested| { - match nested { - syn::NestedMetaItem::MetaItem(syn::MetaItem::List(i)) => { - if i.ident == "assert_instr" { - i.nested.into_iter().next() - } else { - None - } + .filter_map(|nested| match nested { + syn::NestedMetaItem::MetaItem(syn::MetaItem::List(i)) => { + if i.ident == "assert_instr" { + i.nested.into_iter().next() + } else { + None } - _ => None, } + _ => None, }) - .filter_map(|nested| { - match nested { - syn::NestedMetaItem::MetaItem(syn::MetaItem::Term(i)) => Some(i), - _ => None, - } + .filter_map(|nested| match nested { + syn::NestedMetaItem::MetaItem(syn::MetaItem::Term(i)) => Some(i), + _ => None, }) .collect() } -fn find_target_feature(name: syn::Ident, attrs: &[syn::Attribute]) -> syn::Lit { - attrs.iter() +fn find_target_feature( + name: syn::Ident, attrs: &[syn::Attribute] +) -> syn::Lit { + attrs + .iter() .filter_map(|a| a.meta_item()) - .filter_map(|a| { - match a { - syn::MetaItem::NameValue(i) => { - if i.ident == "target_feature" { - Some(i.lit) - } else { - None - } + .filter_map(|a| match a { + syn::MetaItem::NameValue(i) => { + if i.ident == "target_feature" { + Some(i.lit) + } else { + None } - _ => None, } + _ => None, }) .next() - .expect(&format!("failed to find target_feature for {}",name)) + .expect(&format!("failed to find target_feature for {}", name)) } diff --git a/stdsimd-verify/tests/x86-intel.rs b/stdsimd-verify/tests/x86-intel.rs index b4a8a4b2b9..b9a4d119ee 100644 --- a/stdsimd-verify/tests/x86-intel.rs +++ b/stdsimd-verify/tests/x86-intel.rs @@ -72,8 +72,7 @@ x86_functions!(static FUNCTIONS); #[derive(Deserialize)] struct Data { - #[serde(rename = "intrinsic", default)] - intrinsics: Vec, + #[serde(rename = "intrinsic", default)] intrinsics: Vec, } #[derive(Deserialize)] @@ -81,18 +80,14 @@ struct Intrinsic { rettype: String, name: String, tech: String, - #[serde(rename = "CPUID", default)] - cpuid: Vec, - #[serde(rename = "parameter", default)] - parameters: Vec, - #[serde(default)] - instruction: Vec, + #[serde(rename = "CPUID", default)] cpuid: Vec, + #[serde(rename = "parameter", default)] parameters: Vec, + #[serde(default)] instruction: Vec, } #[derive(Deserialize)] struct Parameter { - #[serde(rename = "type")] - type_: String, + #[serde(rename = "type")] type_: String, } #[derive(Deserialize)] @@ -113,18 +108,20 @@ fn verify_all_signatures() { let xml = include_bytes!("../x86-intel.xml"); let xml = &xml[..]; - let data: Data = serde_xml_rs::deserialize(xml).expect("failed to deserialize xml"); + let data: Data = + serde_xml_rs::deserialize(xml).expect("failed to deserialize xml"); let mut map = HashMap::new(); for intrinsic in data.intrinsics.iter() { - // This intrinsic has multiple definitions in the XML, so just ignore it. + // This intrinsic has multiple definitions in the XML, so just ignore + // it. if intrinsic.name == "_mm_prefetch" { - continue + continue; } // These'll need to get added eventually, but right now they have some // duplicate names in the XML which we're not dealing with yet if intrinsic.tech == "AVX-512" { - continue + continue; } assert!(map.insert(&intrinsic.name[..], intrinsic).is_none()); @@ -133,13 +130,14 @@ fn verify_all_signatures() { for rust in FUNCTIONS { // This was ignored above, we ignore it here as well. if rust.name == "_mm_prefetch" { - continue + continue; } // these are all AMD-specific intrinsics - if rust.target_feature.contains("sse4a") || - rust.target_feature.contains("tbm") { - continue + if rust.target_feature.contains("sse4a") + || rust.target_feature.contains("tbm") + { + continue; } let intel = match map.get(rust.name) { @@ -147,15 +145,15 @@ fn verify_all_signatures() { None => panic!("missing intel definition for {}", rust.name), }; - // Verify that all `#[target_feature]` annotations are correct, ensuring - // that we've actually enabled the right instruction set for this - // intrinsic. + // Verify that all `#[target_feature]` annotations are correct, + // ensuring that we've actually enabled the right instruction + // set for this intrinsic. assert!(intel.cpuid.len() > 0, "missing cpuid for {}", rust.name); for cpuid in intel.cpuid.iter() { // this is needed by _xsave and probably some related intrinsics, // but let's just skip it for now. if *cpuid == "XSS" { - continue + continue; } let cpuid = cpuid @@ -163,36 +161,48 @@ fn verify_all_signatures() { .flat_map(|c| c.to_lowercase()) .collect::(); - // Normalize `bmi1` to `bmi` as apparently that's what we're calling - // it. + // Normalize `bmi1` to `bmi` as apparently that's what we're + // calling it. let cpuid = if cpuid == "bmi1" { String::from("bmi") } else { cpuid }; - assert!(rust.target_feature.contains(&cpuid), - "intel cpuid `{}` not in `{}` for {}", - cpuid, - rust.target_feature, - rust.name); + assert!( + rust.target_feature.contains(&cpuid), + "intel cpuid `{}` not in `{}` for {}", + cpuid, + rust.target_feature, + rust.name + ); } // TODO: we should test this, but it generates too many failures right // now if false { if rust.instrs.len() == 0 { - assert_eq!(intel.instruction.len(), 0, - "instruction not listed for {}", rust.name); + assert_eq!( + intel.instruction.len(), + 0, + "instruction not listed for {}", + rust.name + ); // If intel doesn't list any instructions and we do then don't // bother trying to look for instructions in intel, we've just got // some extra assertions on our end. } else if intel.instruction.len() > 0 { for instr in rust.instrs.iter() { - assert!(intel.instruction.iter().any(|a| a.name.starts_with(instr)), - "intel failed to list `{}` as an instruction for `{}`", - instr, rust.name); + assert!( + intel + .instruction + .iter() + .any(|a| a.name.starts_with(instr)), + "intel failed to list `{}` as an instruction for `{}`", + instr, + rust.name + ); } } } @@ -201,9 +211,12 @@ fn verify_all_signatures() { match rust.ret { Some(t) => equate(t, &intel.rettype, &rust.name), None => { - assert!(intel.rettype == "" || intel.rettype == "void", - "{} returns `{}` with intel, void in rust", - rust.name, intel.rettype); + assert!( + intel.rettype == "" || intel.rettype == "void", + "{} returns `{}` with intel, void in rust", + rust.name, + intel.rettype + ); } } @@ -212,13 +225,17 @@ fn verify_all_signatures() { if rust.arguments.len() == 0 { if intel.parameters.len() == 1 { assert_eq!(intel.parameters[0].type_, "void"); - continue + continue; } } // Otherwise we want all parameters to be exactly the same - assert_eq!(rust.arguments.len(), intel.parameters.len(), - "wrong number of arguments on {}", rust.name); + assert_eq!( + rust.arguments.len(), + intel.parameters.len(), + "wrong number of arguments on {}", + rust.name + ); for (a, b) in intel.parameters.iter().zip(rust.arguments) { equate(b, &a.type_, &intel.name); } @@ -255,20 +272,21 @@ fn equate(t: &Type, intel: &str, intrinsic: &str) { (&Type::Ptr(&Type::PrimUnsigned(8)), "const void*") => {} (&Type::Ptr(&Type::PrimUnsigned(8)), "void*") => {} - (&Type::Signed(a, b), "__m128i") | - (&Type::Unsigned(a, b), "__m128i") | - (&Type::Ptr(&Type::Signed(a, b)), "__m128i*") | - (&Type::Ptr(&Type::Unsigned(a, b)), "__m128i*") if a * b == 128 => {} + (&Type::Signed(a, b), "__m128i") + | (&Type::Unsigned(a, b), "__m128i") + | (&Type::Ptr(&Type::Signed(a, b)), "__m128i*") + | (&Type::Ptr(&Type::Unsigned(a, b)), "__m128i*") if a * b == 128 => {} - (&Type::Signed(a, b), "__m256i") | - (&Type::Unsigned(a, b), "__m256i") | - (&Type::Ptr(&Type::Signed(a, b)), "__m256i*") | - (&Type::Ptr(&Type::Unsigned(a, b)), "__m256i*") if (a as u32) * (b as u32) == 256 => {} + (&Type::Signed(a, b), "__m256i") + | (&Type::Unsigned(a, b), "__m256i") + | (&Type::Ptr(&Type::Signed(a, b)), "__m256i*") + | (&Type::Ptr(&Type::Unsigned(a, b)), "__m256i*") + if (a as u32) * (b as u32) == 256 => {} - (&Type::Signed(a, b), "__m64") | - (&Type::Unsigned(a, b), "__m64") | - (&Type::Ptr(&Type::Signed(a, b)), "__m64*") | - (&Type::Ptr(&Type::Unsigned(a, b)), "__m64*") if a * b == 64 => {} + (&Type::Signed(a, b), "__m64") + | (&Type::Unsigned(a, b), "__m64") + | (&Type::Ptr(&Type::Signed(a, b)), "__m64*") + | (&Type::Ptr(&Type::Unsigned(a, b)), "__m64*") if a * b == 64 => {} (&Type::Float(32, 4), "__m128") => {} (&Type::Ptr(&Type::Float(32, 4)), "__m128*") => {} @@ -291,20 +309,24 @@ fn equate(t: &Type, intel: &str, intrinsic: &str) { // Intel says the argument is i32... (&Type::PrimSigned(8), "int") if intrinsic == "_mm_insert_epi8" => {} - // This is a macro (?) in C which seems to mutate its arguments, but that - // means that we're taking pointers to arguments in rust as we're not - // exposing it as a macro. - (&Type::Ptr(&Type::Float(32, 4)), "__m128") if intrinsic == "_MM_TRANSPOSE4_PS" => {} + // This is a macro (?) in C which seems to mutate its arguments, but + // that means that we're taking pointers to arguments in rust + // as we're not exposing it as a macro. + (&Type::Ptr(&Type::Float(32, 4)), "__m128") + if intrinsic == "_MM_TRANSPOSE4_PS" => {} // These intrinsics return an `int` in C but they're always either the // bit 1 or 0 so we switch it to returning `bool` in rust (&Type::Bool, "int") - if intrinsic.starts_with("_mm_comi") && intrinsic.ends_with("_sd") - => {} + if intrinsic.starts_with("_mm_comi") + && intrinsic.ends_with("_sd") => {} (&Type::Bool, "int") - if intrinsic.starts_with("_mm_ucomi") && intrinsic.ends_with("_sd") - => {} + if intrinsic.starts_with("_mm_ucomi") + && intrinsic.ends_with("_sd") => {} - _ => panic!("failed to equate: `{}` and {:?} for {}", intel, t, intrinsic), + _ => panic!( + "failed to equate: `{}` and {:?} for {}", + intel, t, intrinsic + ), } }