Enable const-testing for the ported SIMD intrinsics

This commit is contained in:
sayantn
2025-11-17 02:20:07 +05:30
parent 740b8ba8ad
commit 82ff614b34
18 changed files with 440 additions and 288 deletions
+90 -24
View File
@@ -10,6 +10,10 @@
#![allow(unused)]
#![allow(non_camel_case_types)]
// FIXME: `cfg(minisimd_const)` is used to toggle use of const trait impls, which require a few
// nightly features. Remove this when `const_trait_impls`, `const_cmp` and `const_index` are
// stablilized.
#![allow(unexpected_cfgs)]
// The field is currently left `pub` for convenience in porting tests, many of
// which attempt to just construct it directly. That still works; it's just the
@@ -24,39 +28,32 @@ fn clone(&self) -> Self {
}
}
impl<T: PartialEq, const N: usize> PartialEq for Simd<T, N> {
fn eq(&self, other: &Self) -> bool {
self.as_array() == other.as_array()
}
}
impl<T: core::fmt::Debug, const N: usize> core::fmt::Debug for Simd<T, N> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
<[T; N] as core::fmt::Debug>::fmt(self.as_array(), f)
}
}
impl<T, const N: usize> core::ops::Index<usize> for Simd<T, N> {
type Output = T;
fn index(&self, i: usize) -> &T {
&self.as_array()[i]
}
}
impl<T, const N: usize> Simd<T, N> {
pub const fn from_array(a: [T; N]) -> Self {
Simd(a)
}
pub fn as_array(&self) -> &[T; N] {
pub const fn as_array(&self) -> &[T; N] {
let p: *const Self = self;
unsafe { &*p.cast::<[T; N]>() }
}
pub fn into_array(self) -> [T; N]
pub const fn into_array(self) -> [T; N]
where
T: Copy,
{
*self.as_array()
}
pub const fn splat(a: T) -> Self
where
T: Copy,
{
Self([a; N])
}
}
pub type u8x2 = Simd<u8, 2>;
@@ -109,6 +106,14 @@ impl<T, const N: usize> Simd<T, N> {
pub type i128x2 = Simd<i128, 2>;
pub type i128x4 = Simd<i128, 4>;
pub type usizex2 = Simd<usize, 2>;
pub type usizex4 = Simd<usize, 4>;
pub type usizex8 = Simd<usize, 8>;
pub type isizex2 = Simd<isize, 2>;
pub type isizex4 = Simd<isize, 4>;
pub type isizex8 = Simd<isize, 8>;
pub type f32x2 = Simd<f32, 2>;
pub type f32x4 = Simd<f32, 4>;
pub type f32x8 = Simd<f32, 8>;
@@ -122,7 +127,7 @@ impl<T, const N: usize> Simd<T, N> {
// which attempt to just construct it directly. That still works; it's just the
// `.0` projection that doesn't.
#[repr(simd, packed)]
#[derive(Copy)]
#[derive(Copy, Eq)]
pub struct PackedSimd<T, const N: usize>(pub [T; N]);
impl<T: Copy, const N: usize> Clone for PackedSimd<T, N> {
@@ -131,12 +136,6 @@ fn clone(&self) -> Self {
}
}
impl<T: PartialEq, const N: usize> PartialEq for PackedSimd<T, N> {
fn eq(&self, other: &Self) -> bool {
self.as_array() == other.as_array()
}
}
impl<T: core::fmt::Debug, const N: usize> core::fmt::Debug for PackedSimd<T, N> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
<[T; N] as core::fmt::Debug>::fmt(self.as_array(), f)
@@ -147,14 +146,81 @@ impl<T, const N: usize> PackedSimd<T, N> {
pub const fn from_array(a: [T; N]) -> Self {
PackedSimd(a)
}
pub fn as_array(&self) -> &[T; N] {
pub const fn as_array(&self) -> &[T; N] {
let p: *const Self = self;
unsafe { &*p.cast::<[T; N]>() }
}
pub fn into_array(self) -> [T; N]
pub const fn into_array(self) -> [T; N]
where
T: Copy,
{
*self.as_array()
}
pub const fn splat(a: T) -> Self
where
T: Copy,
{
Self([a; N])
}
}
// As `const_trait_impl` is a language feature with specialized syntax, we have to use them in a way
// such that it doesn't get parsed as Rust code unless `cfg(minisimd_const)` is on. The easiest way
// for that is a macro
macro_rules! impl_traits {
($($const_:ident)?) => {
impl<T: $([$const_])? PartialEq, const N: usize> $($const_)? PartialEq for Simd<T, N> {
fn eq(&self, other: &Self) -> bool {
self.as_array() == other.as_array()
}
}
impl<T, const N: usize> $($const_)? core::ops::Index<usize> for Simd<T, N> {
type Output = T;
fn index(&self, i: usize) -> &T {
&self.as_array()[i]
}
}
impl<T: $([$const_])? PartialEq, const N: usize> $($const_)? PartialEq for PackedSimd<T, N>
{
fn eq(&self, other: &Self) -> bool {
self.as_array() == other.as_array()
}
}
};
}
#[cfg(minisimd_const)]
impl_traits!(const);
#[cfg(not(minisimd_const))]
impl_traits!();
/// Version of `assert_eq` that ignores fancy runtime printing in const context.
/// FIXME: Remove once <https://github.com/rust-lang/rust/issues/119826> is fixed.
#[cfg(minisimd_const)]
#[macro_export]
macro_rules! assert_eq {
($left:expr, $right:expr $(,)?) => {
assert_eq!(
$left,
$right,
concat!("`", stringify!($left), "` == `", stringify!($right), "`")
);
};
($left:expr, $right:expr$(, $($arg:tt)+)?) => {
{
let left = $left;
let right = $right;
// type inference works better with the concrete type on the
// left, but humans work better with the expected on the
// right
assert!(right == left, $($($arg)*),*);
}
};
}
#[cfg(minisimd_const)]
use assert_eq;
+51 -34
View File
@@ -1,6 +1,7 @@
//@ run-pass
//@ ignore-emscripten
//@ ignore-android
//@ compile-flags: --cfg minisimd_const
// FIXME: this test fails on arm-android because the NDK version 14 is too old.
// It needs at least version 18. We disable it on all android build bots because
@@ -8,7 +9,7 @@
// Test that the simd floating-point math intrinsics produce correct results.
#![feature(repr_simd, intrinsics, core_intrinsics)]
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
#![allow(non_camel_case_types)]
#[path = "../../../auxiliary/minisimd.rs"]
@@ -20,7 +21,10 @@
macro_rules! assert_approx_eq_f32 {
($a:expr, $b:expr) => {{
let (a, b) = (&$a, &$b);
assert!((*a - *b).abs() < 1.0e-6, "{} is not approximately equal to {}", *a, *b);
assert!(
(*a - *b).abs() < 1.0e-6,
concat!(stringify!($a), " is not approximately equal to ", stringify!($b))
);
}};
}
macro_rules! assert_approx_eq {
@@ -34,7 +38,7 @@ macro_rules! assert_approx_eq {
}};
}
fn main() {
const fn simple_math() {
let x = f32x4::from_array([1.0, 1.0, 1.0, 1.0]);
let y = f32x4::from_array([-1.0, -1.0, -1.0, -1.0]);
let z = f32x4::from_array([0.0, 0.0, 0.0, 0.0]);
@@ -43,37 +47,7 @@ fn main() {
unsafe {
let r = simd_fabs(y);
assert_approx_eq!(x, r);
let r = simd_fcos(z);
assert_approx_eq!(x, r);
let r = simd_fexp(z);
assert_approx_eq!(x, r);
let r = simd_fexp2(z);
assert_approx_eq!(x, r);
let r = simd_fma(x, h, h);
assert_approx_eq!(x, r);
let r = simd_relaxed_fma(x, h, h);
assert_approx_eq!(x, r);
let r = simd_fsqrt(x);
assert_approx_eq!(x, r);
let r = simd_flog(x);
assert_approx_eq!(z, r);
let r = simd_flog2(x);
assert_approx_eq!(z, r);
let r = simd_flog10(x);
assert_approx_eq!(z, r);
let r = simd_fsin(z);
assert_approx_eq!(z, r);
assert_eq!(x, r);
// rounding functions
let r = simd_floor(h);
@@ -90,5 +64,48 @@ fn main() {
let r = simd_trunc(h);
assert_eq!(z, r);
let r = simd_fma(x, h, h);
assert_approx_eq!(x, r);
let r = simd_relaxed_fma(x, h, h);
assert_approx_eq!(x, r);
}
}
fn special_math() {
let x = f32x4::from_array([1.0, 1.0, 1.0, 1.0]);
let z = f32x4::from_array([0.0, 0.0, 0.0, 0.0]);
unsafe {
let r = simd_fcos(z);
assert_approx_eq!(x, r);
let r = simd_fexp(z);
assert_approx_eq!(x, r);
let r = simd_fexp2(z);
assert_approx_eq!(x, r);
let r = simd_fsqrt(x);
assert_approx_eq!(x, r);
let r = simd_flog(x);
assert_approx_eq!(z, r);
let r = simd_flog2(x);
assert_approx_eq!(z, r);
let r = simd_flog10(x);
assert_approx_eq!(z, r);
let r = simd_fsin(z);
assert_approx_eq!(z, r);
}
}
fn main() {
const { simple_math() };
simple_math();
special_math();
}
+8 -2
View File
@@ -1,9 +1,10 @@
//@ run-pass
//@ ignore-emscripten
//@ compile-flags: --cfg minisimd_const
// Test that the simd_f{min,max} intrinsics produce the correct results.
#![feature(repr_simd, core_intrinsics)]
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
#![allow(non_camel_case_types)]
#[path = "../../../auxiliary/minisimd.rs"]
@@ -12,7 +13,7 @@
use std::intrinsics::simd::*;
fn main() {
const fn minmax() {
let x = f32x4::from_array([1.0, 2.0, 3.0, 4.0]);
let y = f32x4::from_array([2.0, 1.0, 4.0, 3.0]);
@@ -47,3 +48,8 @@ fn main() {
assert_eq!(maxn, y);
}
}
fn main() {
const { minmax() };
minmax();
}
@@ -1,8 +1,9 @@
//@ run-pass
//@ ignore-backends: gcc
//@ compile-flags: --cfg minisimd_const
#![allow(non_camel_case_types)]
#![feature(repr_simd, core_intrinsics)]
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
#[path = "../../../auxiliary/minisimd.rs"]
mod minisimd;
@@ -20,7 +21,7 @@ macro_rules! all_eq {
use std::intrinsics::simd::*;
fn main() {
const fn arithmetic() {
let x1 = i32x4::from_array([1, 2, 3, 4]);
let y1 = U32::<4>::from_array([1, 2, 3, 4]);
let z1 = f32x4::from_array([1.0, 2.0, 3.0, 4.0]);
@@ -224,3 +225,8 @@ fn main() {
all_eq!(simd_cttz(y1), U32::<4>::from_array([0, 1, 0, 2]));
}
}
fn main() {
const { arithmetic() };
arithmetic();
}
@@ -1,8 +1,9 @@
//@ run-pass
//@ ignore-emscripten
//@ compile-flags: --cfg minisimd_const
#![allow(non_camel_case_types)]
#![feature(repr_simd, core_intrinsics)]
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
#[path = "../../../auxiliary/minisimd.rs"]
mod minisimd;
@@ -12,7 +13,7 @@
type I32<const N: usize> = Simd<i32, N>;
fn main() {
const fn saturating() {
// unsigned
{
const M: u32 = u32::MAX;
@@ -84,3 +85,8 @@ fn main() {
}
}
}
fn main() {
const { saturating() };
saturating();
}
+8 -2
View File
@@ -1,7 +1,8 @@
//@ run-pass
//@ ignore-backends: gcc
//@ compile-flags: --cfg minisimd_const
#![feature(repr_simd, core_intrinsics)]
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
#[path = "../../../auxiliary/minisimd.rs"]
mod minisimd;
@@ -11,7 +12,7 @@
type V<T> = Simd<T, 2>;
fn main() {
const fn as_simd() {
unsafe {
let u: V::<u32> = Simd([u32::MIN, u32::MAX]);
let i: V<i16> = simd_as(u);
@@ -47,3 +48,8 @@ fn main() {
assert_eq!(u[1], f[1] as usize);
}
}
fn main() {
const { as_simd() };
as_simd();
}
+16 -24
View File
@@ -1,41 +1,31 @@
//@ run-pass
#![allow(non_camel_case_types)]
//@ ignore-emscripten
//@ ignore-endian-big behavior of simd_bitmask is endian-specific
//@ compile-flags: --cfg minisimd_const
// Test that the simd_bitmask intrinsic produces correct results.
#![feature(repr_simd, core_intrinsics)]
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
#[path = "../../../auxiliary/minisimd.rs"]
mod minisimd;
use minisimd::*;
use std::intrinsics::simd::simd_bitmask;
#[repr(simd)]
#[derive(Copy, Clone, PartialEq, Debug)]
struct u32x4(pub [u32; 4]);
#[repr(simd)]
#[derive(Copy, Clone, PartialEq, Debug)]
struct u8x4(pub [u8; 4]);
#[repr(simd)]
#[derive(Copy, Clone, PartialEq, Debug)]
struct Tx4<T>(pub [T; 4]);
fn main() {
let z = u32x4([0, 0, 0, 0]);
const fn bitmask() {
let z = u32x4::from_array([0, 0, 0, 0]);
let ez = 0_u8;
let o = u32x4([!0, !0, !0, !0]);
let o = u32x4::from_array([!0, !0, !0, !0]);
let eo = 0b_1111_u8;
let m0 = u32x4([!0, 0, !0, 0]);
let m0 = u32x4::from_array([!0, 0, !0, 0]);
let e0 = 0b_0000_0101_u8;
// Check that the MSB is extracted:
let m = u8x4([0b_1000_0000, 0b_0100_0001, 0b_1100_0001, 0b_1111_1111]);
let e = 0b_1101;
// Check usize / isize
let msize: Tx4<usize> = Tx4([usize::MAX, 0, usize::MAX, usize::MAX]);
let msize = usizex4::from_array([usize::MAX, 0, usize::MAX, usize::MAX]);
unsafe {
let r: u8 = simd_bitmask(z);
@@ -47,10 +37,12 @@ fn main() {
let r: u8 = simd_bitmask(m0);
assert_eq!(r, e0);
let r: u8 = simd_bitmask(m);
assert_eq!(r, e);
let r: u8 = simd_bitmask(msize);
assert_eq!(r, e);
}
}
fn main() {
const { bitmask() };
bitmask();
}
@@ -1,6 +1,6 @@
//@ run-pass
#![feature(repr_simd, core_intrinsics)]
#![allow(non_camel_case_types)]
//@ compile-flags: --cfg minisimd_const
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
#[path = "../../../auxiliary/minisimd.rs"]
mod minisimd;
@@ -8,9 +8,14 @@
use std::intrinsics::simd::simd_bswap;
fn main() {
const fn bswap() {
unsafe {
assert_eq!(simd_bswap(i8x4::from_array([0, 1, 2, 3])).into_array(), [0, 1, 2, 3]);
assert_eq!(simd_bswap(u8x4::from_array([0, 1, 2, 3])).into_array(), [0, 1, 2, 3]);
}
}
fn main() {
const { bswap() };
bswap();
}
+8 -2
View File
@@ -1,6 +1,7 @@
//@ run-pass
//@ compile-flags: --cfg minisimd_const
#![feature(repr_simd, core_intrinsics)]
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
#[path = "../../../auxiliary/minisimd.rs"]
mod minisimd;
@@ -12,7 +13,7 @@
type V<T> = Simd<T, 2>;
fn main() {
const fn cast() {
unsafe {
let u: V::<u32> = Simd([i16::MIN as u32, i16::MAX as u32]);
let i: V<i16> = simd_cast(u);
@@ -56,3 +57,8 @@ fn main() {
assert_eq!(u[1], f[1] as usize);
}
}
fn main() {
const { cast() };
cast();
}
@@ -1,5 +1,6 @@
//@ run-pass
#![feature(repr_simd, core_intrinsics)]
//@ compile-flags: --cfg minisimd_const
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
#[path = "../../../auxiliary/minisimd.rs"]
mod minisimd;
@@ -9,17 +10,16 @@
type V<T> = Simd<T, 4>;
fn main() {
const fn cast_ptr_width() {
let u: V::<usize> = Simd([0, 1, 2, 3]);
let uu32: V<u32> = unsafe { simd_cast(u) };
let ui64: V<i64> = unsafe { simd_cast(u) };
for (u, (uu32, ui64)) in u
.as_array()
.iter()
.zip(uu32.as_array().iter().zip(ui64.as_array().iter()))
{
assert_eq!(*u as u32, *uu32);
assert_eq!(*u as i64, *ui64);
}
assert_eq!(uu32, V::<u32>::from_array([0, 1, 2, 3]));
assert_eq!(ui64, V::<i64>::from_array([0, 1, 2, 3]));
}
fn main() {
const { cast_ptr_width() };
cast_ptr_width();
}
@@ -1,7 +1,14 @@
//@ run-pass
//@ compile-flags: --cfg minisimd_const
#![feature(repr_simd, core_intrinsics, macro_metavar_expr_concat)]
#![allow(non_camel_case_types)]
#![feature(
repr_simd,
core_intrinsics,
const_trait_impl,
const_cmp,
const_index,
macro_metavar_expr_concat
)]
#[path = "../../../auxiliary/minisimd.rs"]
mod minisimd;
@@ -25,27 +32,26 @@ macro_rules! cmp {
macro_rules! tests {
($($lhs: ident, $rhs: ident;)*) => {{
$(
(|| {
cmp!(eq($lhs, $rhs));
cmp!(ne($lhs, $rhs));
cmp!(eq($lhs, $rhs));
cmp!(ne($lhs, $rhs));
// test both directions
cmp!(lt($lhs, $rhs));
cmp!(lt($rhs, $lhs));
// test both directions
cmp!(lt($lhs, $rhs));
cmp!(lt($rhs, $lhs));
cmp!(le($lhs, $rhs));
cmp!(le($rhs, $lhs));
cmp!(le($lhs, $rhs));
cmp!(le($rhs, $lhs));
cmp!(gt($lhs, $rhs));
cmp!(gt($rhs, $lhs));
cmp!(gt($lhs, $rhs));
cmp!(gt($rhs, $lhs));
cmp!(ge($lhs, $rhs));
cmp!(ge($rhs, $lhs));
})();
)*
cmp!(ge($lhs, $rhs));
cmp!(ge($rhs, $lhs));
)*
}}
}
fn main() {
const fn compare() {
// 13 vs. -100 tests that we get signed vs. unsigned comparisons
// correct (i32: 13 > -100, u32: 13 < -100). let i1 = i32x4(10, -11, 12, 13);
let i1 = i32x4::from_array([10, -11, 12, 13]);
@@ -89,3 +95,8 @@ fn main() {
}
}
}
fn main() {
const { compare() };
compare();
}
@@ -1,6 +1,7 @@
//@ run-pass
//@ compile-flags: --cfg minisimd_const
#![feature(repr_simd, intrinsics, core_intrinsics)]
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
#[path = "../../../auxiliary/minisimd.rs"]
mod minisimd;
@@ -20,11 +21,59 @@ macro_rules! all_eq {
// type inference works better with the concrete type on the
// left, but humans work better with the expected on the
// right.
assert!(b == a, "{:?} != {:?}", a, b);
assert!(b == a, concat!(stringify!($a), "!=", stringify!($b)));
}};
}
fn main() {
fn extract_insert_dyn() {
let x2 = i32x2::from_array([20, 21]);
let x4 = i32x4::from_array([40, 41, 42, 43]);
let x8 = i32x8::from_array([80, 81, 82, 83, 84, 85, 86, 87]);
unsafe {
all_eq!(simd_insert_dyn(x2, 0, 100), i32x2::from_array([100, 21]));
all_eq!(simd_insert_dyn(x2, 1, 100), i32x2::from_array([20, 100]));
all_eq!(simd_insert_dyn(x4, 0, 100), i32x4::from_array([100, 41, 42, 43]));
all_eq!(simd_insert_dyn(x4, 1, 100), i32x4::from_array([40, 100, 42, 43]));
all_eq!(simd_insert_dyn(x4, 2, 100), i32x4::from_array([40, 41, 100, 43]));
all_eq!(simd_insert_dyn(x4, 3, 100), i32x4::from_array([40, 41, 42, 100]));
all_eq!(simd_insert_dyn(x8, 0, 100), i32x8::from_array([100, 81, 82, 83, 84, 85, 86, 87]));
all_eq!(simd_insert_dyn(x8, 1, 100), i32x8::from_array([80, 100, 82, 83, 84, 85, 86, 87]));
all_eq!(simd_insert_dyn(x8, 2, 100), i32x8::from_array([80, 81, 100, 83, 84, 85, 86, 87]));
all_eq!(simd_insert_dyn(x8, 3, 100), i32x8::from_array([80, 81, 82, 100, 84, 85, 86, 87]));
all_eq!(simd_insert_dyn(x8, 4, 100), i32x8::from_array([80, 81, 82, 83, 100, 85, 86, 87]));
all_eq!(simd_insert_dyn(x8, 5, 100), i32x8::from_array([80, 81, 82, 83, 84, 100, 86, 87]));
all_eq!(simd_insert_dyn(x8, 6, 100), i32x8::from_array([80, 81, 82, 83, 84, 85, 100, 87]));
all_eq!(simd_insert_dyn(x8, 7, 100), i32x8::from_array([80, 81, 82, 83, 84, 85, 86, 100]));
all_eq!(simd_extract_dyn(x2, 0), 20);
all_eq!(simd_extract_dyn(x2, 1), 21);
all_eq!(simd_extract_dyn(x4, 0), 40);
all_eq!(simd_extract_dyn(x4, 1), 41);
all_eq!(simd_extract_dyn(x4, 2), 42);
all_eq!(simd_extract_dyn(x4, 3), 43);
all_eq!(simd_extract_dyn(x8, 0), 80);
all_eq!(simd_extract_dyn(x8, 1), 81);
all_eq!(simd_extract_dyn(x8, 2), 82);
all_eq!(simd_extract_dyn(x8, 3), 83);
all_eq!(simd_extract_dyn(x8, 4), 84);
all_eq!(simd_extract_dyn(x8, 5), 85);
all_eq!(simd_extract_dyn(x8, 6), 86);
all_eq!(simd_extract_dyn(x8, 7), 87);
}
}
macro_rules! simd_shuffle {
($a:expr, $b:expr, $swizzle:expr) => {
simd_shuffle($a, $b, const { SimdShuffleIdx($swizzle) })
};
}
const fn swizzle() {
let x2 = i32x2::from_array([20, 21]);
let x4 = i32x4::from_array([40, 41, 42, 43]);
let x8 = i32x8::from_array([80, 81, 82, 83, 84, 85, 86, 87]);
@@ -63,83 +112,36 @@ fn main() {
all_eq!(simd_extract(x8, 6), 86);
all_eq!(simd_extract(x8, 7), 87);
}
unsafe {
all_eq!(simd_insert_dyn(x2, 0, 100), i32x2::from_array([100, 21]));
all_eq!(simd_insert_dyn(x2, 1, 100), i32x2::from_array([20, 100]));
all_eq!(simd_insert_dyn(x4, 0, 100), i32x4::from_array([100, 41, 42, 43]));
all_eq!(simd_insert_dyn(x4, 1, 100), i32x4::from_array([40, 100, 42, 43]));
all_eq!(simd_insert_dyn(x4, 2, 100), i32x4::from_array([40, 41, 100, 43]));
all_eq!(simd_insert_dyn(x4, 3, 100), i32x4::from_array([40, 41, 42, 100]));
all_eq!(simd_insert_dyn(x8, 0, 100), i32x8::from_array([100, 81, 82, 83, 84, 85, 86, 87]));
all_eq!(simd_insert_dyn(x8, 1, 100), i32x8::from_array([80, 100, 82, 83, 84, 85, 86, 87]));
all_eq!(simd_insert_dyn(x8, 2, 100), i32x8::from_array([80, 81, 100, 83, 84, 85, 86, 87]));
all_eq!(simd_insert_dyn(x8, 3, 100), i32x8::from_array([80, 81, 82, 100, 84, 85, 86, 87]));
all_eq!(simd_insert_dyn(x8, 4, 100), i32x8::from_array([80, 81, 82, 83, 100, 85, 86, 87]));
all_eq!(simd_insert_dyn(x8, 5, 100), i32x8::from_array([80, 81, 82, 83, 84, 100, 86, 87]));
all_eq!(simd_insert_dyn(x8, 6, 100), i32x8::from_array([80, 81, 82, 83, 84, 85, 100, 87]));
all_eq!(simd_insert_dyn(x8, 7, 100), i32x8::from_array([80, 81, 82, 83, 84, 85, 86, 100]));
all_eq!(simd_extract_dyn(x2, 0), 20);
all_eq!(simd_extract_dyn(x2, 1), 21);
all_eq!(simd_extract_dyn(x4, 0), 40);
all_eq!(simd_extract_dyn(x4, 1), 41);
all_eq!(simd_extract_dyn(x4, 2), 42);
all_eq!(simd_extract_dyn(x4, 3), 43);
all_eq!(simd_extract_dyn(x8, 0), 80);
all_eq!(simd_extract_dyn(x8, 1), 81);
all_eq!(simd_extract_dyn(x8, 2), 82);
all_eq!(simd_extract_dyn(x8, 3), 83);
all_eq!(simd_extract_dyn(x8, 4), 84);
all_eq!(simd_extract_dyn(x8, 5), 85);
all_eq!(simd_extract_dyn(x8, 6), 86);
all_eq!(simd_extract_dyn(x8, 7), 87);
}
let y2 = i32x2::from_array([120, 121]);
let y4 = i32x4::from_array([140, 141, 142, 143]);
let y8 = i32x8::from_array([180, 181, 182, 183, 184, 185, 186, 187]);
unsafe {
all_eq!(simd_shuffle!(x2, y2, [3u32, 0]), i32x2::from_array([121, 20]));
all_eq!(simd_shuffle!(x2, y2, [3u32, 0, 1, 2]), i32x4::from_array([121, 20, 21, 120]));
all_eq!(
simd_shuffle(x2, y2, const { SimdShuffleIdx([3u32, 0]) }),
i32x2::from_array([121, 20])
);
all_eq!(
simd_shuffle(x2, y2, const { SimdShuffleIdx([3u32, 0, 1, 2]) }),
i32x4::from_array([121, 20, 21, 120])
);
all_eq!(
simd_shuffle(x2, y2, const { SimdShuffleIdx([3u32, 0, 1, 2, 1, 2, 3, 0]) }),
simd_shuffle!(x2, y2, [3u32, 0, 1, 2, 1, 2, 3, 0]),
i32x8::from_array([121, 20, 21, 120, 21, 120, 121, 20])
);
all_eq!(simd_shuffle!(x4, y4, [7u32, 2]), i32x2::from_array([143, 42]));
all_eq!(simd_shuffle!(x4, y4, [7u32, 2, 5, 0]), i32x4::from_array([143, 42, 141, 40]));
all_eq!(
simd_shuffle(x4, y4, const { SimdShuffleIdx([7u32, 2]) }),
i32x2::from_array([143, 42])
);
all_eq!(
simd_shuffle(x4, y4, const { SimdShuffleIdx([7u32, 2, 5, 0]) }),
i32x4::from_array([143, 42, 141, 40])
);
all_eq!(
simd_shuffle(x4, y4, const { SimdShuffleIdx([7u32, 2, 5, 0, 3, 6, 4, 1]) }),
simd_shuffle!(x4, y4, [7u32, 2, 5, 0, 3, 6, 4, 1]),
i32x8::from_array([143, 42, 141, 40, 43, 142, 140, 41])
);
all_eq!(simd_shuffle!(x8, y8, [11u32, 5]), i32x2::from_array([183, 85]));
all_eq!(simd_shuffle!(x8, y8, [11u32, 5, 15, 0]), i32x4::from_array([183, 85, 187, 80]));
all_eq!(
simd_shuffle(x8, y8, const { SimdShuffleIdx([11u32, 5]) }),
i32x2::from_array([183, 85])
);
all_eq!(
simd_shuffle(x8, y8, const { SimdShuffleIdx([11u32, 5, 15, 0]) }),
i32x4::from_array([183, 85, 187, 80])
);
all_eq!(
simd_shuffle(x8, y8, const { SimdShuffleIdx([11u32, 5, 15, 0, 3, 8, 12, 1]) }),
simd_shuffle!(x8, y8, [11u32, 5, 15, 0, 3, 8, 12, 1]),
i32x8::from_array([183, 85, 187, 80, 83, 180, 184, 81])
);
}
}
fn main() {
extract_insert_dyn();
const { swizzle() };
swizzle();
}
@@ -1,9 +1,10 @@
//@ run-pass
//@ ignore-emscripten
//@ compile-flags: --cfg minisimd_const
// Test that the simd_{gather,scatter} intrinsics produce the correct results.
#![feature(repr_simd, core_intrinsics)]
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
#![allow(non_camel_case_types)]
#[path = "../../../auxiliary/minisimd.rs"]
@@ -14,48 +15,11 @@
type x4<T> = Simd<T, 4>;
fn main() {
let mut x = [0_f32, 1., 2., 3., 4., 5., 6., 7.];
let default = x4::from_array([-3_f32, -3., -3., -3.]);
let s_strided = x4::from_array([0_f32, 2., -3., 6.]);
fn gather_scatter_of_ptrs() {
// test modifying array of *const f32
let x = [0_f32, 1., 2., 3., 4., 5., 6., 7.];
let mask = x4::from_array([-1_i32, -1, 0, -1]);
// reading from *const
unsafe {
let pointer = x.as_ptr();
let pointers =
x4::from_array(std::array::from_fn(|i| pointer.add(i * 2)));
let r_strided = simd_gather(default, pointers, mask);
assert_eq!(r_strided, s_strided);
}
// reading from *mut
unsafe {
let pointer = x.as_mut_ptr();
let pointers =
x4::from_array(std::array::from_fn(|i| pointer.add(i * 2)));
let r_strided = simd_gather(default, pointers, mask);
assert_eq!(r_strided, s_strided);
}
// writing to *mut
unsafe {
let pointer = x.as_mut_ptr();
let pointers =
x4::from_array(std::array::from_fn(|i| pointer.add(i * 2)));
let values = x4::from_array([42_f32, 43_f32, 44_f32, 45_f32]);
simd_scatter(values, pointers, mask);
assert_eq!(x, [42., 1., 43., 3., 4., 5., 45., 7.]);
}
// test modifying array of *const f32
let mut y = [
&x[0] as *const f32,
&x[1] as *const f32,
@@ -73,8 +37,7 @@ fn main() {
// reading from *const
unsafe {
let pointer = y.as_ptr();
let pointers =
x4::from_array(std::array::from_fn(|i| pointer.add(i * 2)));
let pointers = x4::from_array([pointer, pointer.add(2), pointer.add(4), pointer.add(6)]);
let r_strided = simd_gather(default, pointers, mask);
@@ -84,8 +47,7 @@ fn main() {
// reading from *mut
unsafe {
let pointer = y.as_mut_ptr();
let pointers =
x4::from_array(std::array::from_fn(|i| pointer.add(i * 2)));
let pointers = x4::from_array([pointer, pointer.add(2), pointer.add(4), pointer.add(6)]);
let r_strided = simd_gather(default, pointers, mask);
@@ -95,8 +57,7 @@ fn main() {
// writing to *mut
unsafe {
let pointer = y.as_mut_ptr();
let pointers =
x4::from_array(std::array::from_fn(|i| pointer.add(i * 2)));
let pointers = x4::from_array([pointer, pointer.add(2), pointer.add(4), pointer.add(6)]);
let values = x4::from_array([y[7], y[6], y[5], y[1]]);
simd_scatter(values, pointers, mask);
@@ -114,3 +75,48 @@ fn main() {
assert_eq!(y, s);
}
}
const fn gather_scatter() {
let mut x = [0_f32, 1., 2., 3., 4., 5., 6., 7.];
let default = x4::from_array([-3_f32, -3., -3., -3.]);
let s_strided = x4::from_array([0_f32, 2., -3., 6.]);
let mask = x4::from_array([-1_i32, -1, 0, -1]);
// reading from *const
unsafe {
let pointer = x.as_ptr();
let pointers = x4::from_array([pointer, pointer.add(2), pointer.add(4), pointer.add(6)]);
let r_strided = simd_gather(default, pointers, mask);
assert_eq!(r_strided, s_strided);
}
// reading from *mut
unsafe {
let pointer = x.as_mut_ptr();
let pointers = x4::from_array([pointer, pointer.add(2), pointer.add(4), pointer.add(6)]);
let r_strided = simd_gather(default, pointers, mask);
assert_eq!(r_strided, s_strided);
}
// writing to *mut
unsafe {
let pointer = x.as_mut_ptr();
let pointers = x4::from_array([pointer, pointer.add(2), pointer.add(4), pointer.add(6)]);
let values = x4::from_array([42_f32, 43_f32, 44_f32, 45_f32]);
simd_scatter(values, pointers, mask);
assert_eq!(x, [42., 1., 43., 3., 4., 5., 45., 7.]);
}
}
fn main() {
const { gather_scatter() };
gather_scatter();
gather_scatter_of_ptrs();
}
@@ -1,35 +1,46 @@
//@ run-pass
#![allow(non_camel_case_types)]
//@ ignore-emscripten
//@ compile-flags: --cfg minisimd_const
// Test that the simd_reduce_{op} intrinsics produce the correct results.
#![feature(repr_simd, core_intrinsics)]
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
#[path = "../../../auxiliary/minisimd.rs"]
mod minisimd;
use minisimd::*;
use std::intrinsics::simd::*;
#[repr(simd)]
#[derive(Copy, Clone)]
struct i32x4(pub [i32; 4]);
#[repr(simd)]
#[derive(Copy, Clone)]
struct u32x4(pub [u32; 4]);
#[repr(simd)]
#[derive(Copy, Clone)]
struct f32x4(pub [f32; 4]);
#[repr(simd)]
#[derive(Copy, Clone)]
struct b8x4(pub [i8; 4]);
fn main() {
fn unordered() {
unsafe {
let x = i32x4([1, -2, 3, 4]);
let x = i32x4::from_array([1, -2, 3, 4]);
let r: i32 = simd_reduce_add_unordered(x);
assert_eq!(r, 6_i32);
let r: i32 = simd_reduce_mul_unordered(x);
assert_eq!(r, -24_i32);
}
unsafe {
let x = u32x4::from_array([1, 2, 3, 4]);
let r: u32 = simd_reduce_add_unordered(x);
assert_eq!(r, 10_u32);
let r: u32 = simd_reduce_mul_unordered(x);
assert_eq!(r, 24_u32);
}
unsafe {
let x = f32x4::from_array([1., -2., 3., 4.]);
let r: f32 = simd_reduce_add_unordered(x);
assert_eq!(r, 6_f32);
let r: f32 = simd_reduce_mul_unordered(x);
assert_eq!(r, -24_f32);
}
}
const fn ordered() {
unsafe {
let x = i32x4::from_array([1, -2, 3, 4]);
let r: i32 = simd_reduce_add_ordered(x, -1);
assert_eq!(r, 5_i32);
let r: i32 = simd_reduce_mul_ordered(x, -1);
@@ -40,7 +51,7 @@ fn main() {
let r: i32 = simd_reduce_max(x);
assert_eq!(r, 4_i32);
let x = i32x4([-1, -1, -1, -1]);
let x = i32x4::from_array([-1, -1, -1, -1]);
let r: i32 = simd_reduce_and(x);
assert_eq!(r, -1_i32);
let r: i32 = simd_reduce_or(x);
@@ -48,7 +59,7 @@ fn main() {
let r: i32 = simd_reduce_xor(x);
assert_eq!(r, 0_i32);
let x = i32x4([-1, -1, 0, -1]);
let x = i32x4::from_array([-1, -1, 0, -1]);
let r: i32 = simd_reduce_and(x);
assert_eq!(r, 0_i32);
let r: i32 = simd_reduce_or(x);
@@ -58,11 +69,7 @@ fn main() {
}
unsafe {
let x = u32x4([1, 2, 3, 4]);
let r: u32 = simd_reduce_add_unordered(x);
assert_eq!(r, 10_u32);
let r: u32 = simd_reduce_mul_unordered(x);
assert_eq!(r, 24_u32);
let x = u32x4::from_array([1, 2, 3, 4]);
let r: u32 = simd_reduce_add_ordered(x, 1);
assert_eq!(r, 11_u32);
let r: u32 = simd_reduce_mul_ordered(x, 2);
@@ -74,7 +81,7 @@ fn main() {
assert_eq!(r, 4_u32);
let t = u32::MAX;
let x = u32x4([t, t, t, t]);
let x = u32x4::from_array([t, t, t, t]);
let r: u32 = simd_reduce_and(x);
assert_eq!(r, t);
let r: u32 = simd_reduce_or(x);
@@ -82,7 +89,7 @@ fn main() {
let r: u32 = simd_reduce_xor(x);
assert_eq!(r, 0_u32);
let x = u32x4([t, t, 0, t]);
let x = u32x4::from_array([t, t, 0, t]);
let r: u32 = simd_reduce_and(x);
assert_eq!(r, 0_u32);
let r: u32 = simd_reduce_or(x);
@@ -92,11 +99,7 @@ fn main() {
}
unsafe {
let x = f32x4([1., -2., 3., 4.]);
let r: f32 = simd_reduce_add_unordered(x);
assert_eq!(r, 6_f32);
let r: f32 = simd_reduce_mul_unordered(x);
assert_eq!(r, -24_f32);
let x = f32x4::from_array([1., -2., 3., 4.]);
let r: f32 = simd_reduce_add_ordered(x, 0.);
assert_eq!(r, 6_f32);
let r: f32 = simd_reduce_mul_ordered(x, 1.);
@@ -113,22 +116,28 @@ fn main() {
}
unsafe {
let x = b8x4([!0, !0, !0, !0]);
let x = i8x4::from_array([!0, !0, !0, !0]);
let r: bool = simd_reduce_all(x);
assert_eq!(r, true);
let r: bool = simd_reduce_any(x);
assert_eq!(r, true);
let x = b8x4([!0, !0, 0, !0]);
let x = i8x4::from_array([!0, !0, 0, !0]);
let r: bool = simd_reduce_all(x);
assert_eq!(r, false);
let r: bool = simd_reduce_any(x);
assert_eq!(r, true);
let x = b8x4([0, 0, 0, 0]);
let x = i8x4::from_array([0, 0, 0, 0]);
let r: bool = simd_reduce_all(x);
assert_eq!(r, false);
let r: bool = simd_reduce_any(x);
assert_eq!(r, false);
}
}
fn main() {
unordered();
const { ordered() };
ordered();
}
@@ -2,9 +2,10 @@
#![allow(non_camel_case_types)]
//@ ignore-emscripten
//@ ignore-endian-big behavior of simd_select_bitmask is endian-specific
//@ compile-flags: --cfg minisimd_const
// Test that the simd_select intrinsics produces correct results.
#![feature(repr_simd, core_intrinsics)]
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
#[path = "../../../auxiliary/minisimd.rs"]
mod minisimd;
@@ -14,7 +15,7 @@
type b8x4 = i8x4;
fn main() {
const fn select() {
let m0 = b8x4::from_array([!0, !0, !0, !0]);
let m1 = b8x4::from_array([0, 0, 0, 0]);
let m2 = b8x4::from_array([!0, !0, 0, 0]);
@@ -173,3 +174,8 @@ fn main() {
assert_eq!(r, e);
}
}
fn main() {
const { select() };
select();
}
+8 -2
View File
@@ -1,6 +1,7 @@
//@ ignore-backends: gcc
//@ compile-flags: --cfg minisimd_const
//@ run-pass
#![feature(repr_simd, core_intrinsics)]
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
#[path = "../../auxiliary/minisimd.rs"]
mod minisimd;
@@ -8,7 +9,7 @@
use std::intrinsics::simd::{SimdAlign, simd_masked_load, simd_masked_store};
fn main() {
const fn masked_load_store() {
unsafe {
let a = Simd::<u8, 4>([0, 1, 2, 3]);
let b_src = [4u8, 5, 6, 7];
@@ -37,3 +38,8 @@ fn main() {
assert_eq!(&output, &[0, 1, 9, 6, u8::MAX]);
}
}
fn main() {
const { masked_load_store() };
masked_load_store();
}
+8 -12
View File
@@ -3,8 +3,9 @@
// This should be merged into `simd-bitmask` once that's fixed.
//@ ignore-endian-big
//@ ignore-backends: gcc
//@ compile-flags: --cfg minisimd_const
#![feature(repr_simd, core_intrinsics)]
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
#[path = "../../auxiliary/minisimd.rs"]
mod minisimd;
@@ -12,15 +13,10 @@
use std::intrinsics::simd::{simd_bitmask, simd_select_bitmask};
fn main() {
const fn bitmask() {
// Non-power-of-2 multi-byte mask.
#[allow(non_camel_case_types)]
type i32x10 = PackedSimd<i32, 10>;
impl i32x10 {
fn splat(x: i32) -> Self {
Self([x; 10])
}
}
unsafe {
let mask = i32x10::from_array([!0, !0, 0, !0, 0, 0, !0, 0, !0, 0]);
let mask_bits = if cfg!(target_endian = "little") { 0b0101001011 } else { 0b1101001010 };
@@ -49,11 +45,6 @@ fn splat(x: i32) -> Self {
// Test for a mask where the next multiple of 8 is not a power of two.
#[allow(non_camel_case_types)]
type i32x20 = PackedSimd<i32, 20>;
impl i32x20 {
fn splat(x: i32) -> Self {
Self([x; 20])
}
}
unsafe {
let mask = i32x20::from_array([
!0, !0, 0, !0, 0,
@@ -91,3 +82,8 @@ fn splat(x: i32) -> Self {
assert_eq!(selected2, mask);
}
}
fn main() {
const { bitmask() };
bitmask();
}
+8 -2
View File
@@ -1,5 +1,6 @@
//@run-pass
#![feature(repr_simd, core_intrinsics)]
//@ compile-flags: --cfg minisimd_const
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
#[path = "../../auxiliary/minisimd.rs"]
mod minisimd;
@@ -7,7 +8,7 @@
use std::intrinsics::simd::{simd_bitmask, simd_select_bitmask};
fn main() {
const fn bitmask() {
unsafe {
let v = Simd::<i8, 4>([-1, 0, -1, 0]);
let i: u8 = simd_bitmask(v);
@@ -68,3 +69,8 @@ fn main() {
assert_eq!(r.into_array(), e);
}
}
fn main() {
const { bitmask() };
bitmask();
}