From cf10e913390d1f55c7a5a82e84e7f8bfd41d90f7 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 18 Jan 2025 13:52:06 +0100 Subject: [PATCH] implement `VectorAdd` for `s390x` --- ci/run.sh | 4 - crates/core_arch/src/mod.rs | 2 +- crates/core_arch/src/s390x/macros.rs | 354 +++++++++++++++++++++++++++ crates/core_arch/src/s390x/mod.rs | 4 +- crates/core_arch/src/s390x/vector.rs | 163 +++++++++++- 5 files changed, 518 insertions(+), 9 deletions(-) create mode 100644 crates/core_arch/src/s390x/macros.rs diff --git a/ci/run.sh b/ci/run.sh index 2ea5504492..28d53c5375 100755 --- a/ci/run.sh +++ b/ci/run.sh @@ -124,10 +124,6 @@ case ${TARGET} in export RUSTFLAGS="${RUSTFLAGS} -C target-feature=+msa" cargo_test "${PROFILE}" ;; - s390x*) - export RUSTFLAGS="${RUSTFLAGS} -C target-feature=+vector" - cargo_test "${PROFILE}" - ;; powerpc64*) # We don't build the ppc 32-bit targets with these - these targets # are mostly unsupported for now. diff --git a/crates/core_arch/src/mod.rs b/crates/core_arch/src/mod.rs index 8f1da6ffe7..87ce18ca7b 100644 --- a/crates/core_arch/src/mod.rs +++ b/crates/core_arch/src/mod.rs @@ -284,7 +284,7 @@ pub mod arch { /// See the [module documentation](../index.html) for more details. #[cfg(any(target_arch = "s390x", doc))] #[doc(cfg(target_arch = "s390x"))] - #[unstable(feature = "stdarch_s390x", issue = "1")] + #[unstable(feature = "stdarch_s390x", issue = "135681")] pub mod s390x { pub use crate::core_arch::s390x::*; } diff --git a/crates/core_arch/src/s390x/macros.rs b/crates/core_arch/src/s390x/macros.rs new file mode 100644 index 0000000000..87936715ea --- /dev/null +++ b/crates/core_arch/src/s390x/macros.rs @@ -0,0 +1,354 @@ +#![allow(unused_macros)] // FIXME remove when more tests are added +#![allow(unused_imports)] // FIXME remove when more tests are added + +macro_rules! test_impl { + ($fun:ident ($($v:ident : $ty:ty),*) -> $r:ty [$call:ident, $instr:ident]) => { + #[inline] + #[target_feature(enable = "vector")] + #[cfg_attr(test, assert_instr($instr))] + pub unsafe fn $fun ($($v : $ty),*) -> $r { + $call ($($v),*) + } + }; +} + +#[allow(unknown_lints, unused_macro_rules)] +macro_rules! impl_vec_trait { + ([$Trait:ident $m:ident] $fun:ident ($a:ty)) => { + #[unstable(feature = "stdarch_s390x", issue = "135681")] + impl $Trait for $a { + #[inline] + #[target_feature(enable = "vector")] + unsafe fn $m(self) -> Self { + $fun(transmute(self)) + } + } + }; + ([$Trait:ident $m:ident] $fun:ident ($a:ty) -> $r:ty) => { + #[unstable(feature = "stdarch_s390x", issue = "135681")] + impl $Trait for $a { + type Result = $r; + #[inline] + #[target_feature(enable = "vector")] + unsafe fn $m(self) -> Self::Result { + $fun(transmute(self)) + } + } + }; + ([$Trait:ident $m:ident]+ $fun:ident ($a:ty) -> $r:ty) => { + #[unstable(feature = "stdarch_s390x", issue = "135681")] + impl $Trait for $a { + type Result = $r; + #[inline] + #[target_feature(enable = "vector")] + unsafe fn $m(self) -> Self::Result { + transmute($fun(transmute(self))) + } + } + }; + ([$Trait:ident $m:ident] 1 ($ub:ident, $sb:ident, $uh:ident, $sh:ident, $uw:ident, $sw:ident, $sf: ident)) => { + impl_vec_trait!{ [$Trait $m] $ub (vector_unsigned_char) -> vector_unsigned_char } + impl_vec_trait!{ [$Trait $m] $sb (vector_signed_char) -> vector_signed_char } + impl_vec_trait!{ [$Trait $m] $uh (vector_unsigned_short) -> vector_unsigned_short } + impl_vec_trait!{ [$Trait $m] $sh (vector_signed_short) -> vector_signed_short } + impl_vec_trait!{ [$Trait $m] $uw (vector_unsigned_int) -> vector_unsigned_int } + impl_vec_trait!{ [$Trait $m] $sw (vector_signed_int) -> vector_signed_int } + impl_vec_trait!{ [$Trait $m] $uw (vector_unsigned_long_long) -> vector_unsigned_long_long } + impl_vec_trait!{ [$Trait $m] $sw (vector_signed_long_long) -> vector_signed_long_long } + impl_vec_trait!{ [$Trait $m] $sf (vector_float) -> vector_float } + impl_vec_trait!{ [$Trait $m] $sf (vector_double) -> vector_double } + }; + ([$Trait:ident $m:ident] $fun:ident ($a:ty, $b:ty) -> $r:ty) => { + #[unstable(feature = "stdarch_s390x", issue = "135681")] + impl $Trait<$b> for $a { + type Result = $r; + #[inline] + #[target_feature(enable = "vector")] + unsafe fn $m(self, b: $b) -> Self::Result { + $fun(transmute(self), transmute(b)) + } + } + }; + ([$Trait:ident $m:ident]+ $fun:ident ($a:ty, $b:ty) -> $r:ty) => { + #[unstable(feature = "stdarch_s390x", issue = "135681")] + impl $Trait<$b> for $a { + type Result = $r; + #[inline] + #[target_feature(enable = "vector")] + unsafe fn $m(self, b: $b) -> Self::Result { + transmute($fun(transmute(self), transmute(b))) + } + } + }; + ([$Trait:ident $m:ident] $fun:ident ($a:ty, ~$b:ty) -> $r:ty) => { + impl_vec_trait!{ [$Trait $m] $fun ($a, $a) -> $r } + impl_vec_trait!{ [$Trait $m] $fun ($a, $b) -> $r } + impl_vec_trait!{ [$Trait $m] $fun ($b, $a) -> $r } + }; + ([$Trait:ident $m:ident] ~($ub:ident, $sb:ident, $uh:ident, $sh:ident, $uw:ident, $sw:ident)) => { + impl_vec_trait!{ [$Trait $m] $ub (vector_unsigned_char, ~vector_bool_char) -> vector_unsigned_char } + impl_vec_trait!{ [$Trait $m] $sb (vector_signed_char, ~vector_bool_char) -> vector_signed_char } + impl_vec_trait!{ [$Trait $m] $uh (vector_unsigned_short, ~vector_bool_short) -> vector_unsigned_short } + impl_vec_trait!{ [$Trait $m] $sh (vector_signed_short, ~vector_bool_short) -> vector_signed_short } + impl_vec_trait!{ [$Trait $m] $uw (vector_unsigned_int, ~vector_bool_int) -> vector_unsigned_int } + impl_vec_trait!{ [$Trait $m] $sw (vector_signed_int, ~vector_bool_int) -> vector_signed_int } + }; + ([$Trait:ident $m:ident] ~($fn:ident)) => { + impl_vec_trait!{ [$Trait $m] ~($fn, $fn, $fn, $fn, $fn, $fn) } + }; + ([$Trait:ident $m:ident] 2 ($ub:ident, $sb:ident, $uh:ident, $sh:ident, $uw:ident, $sw:ident)) => { + impl_vec_trait!{ [$Trait $m] $ub (vector_unsigned_char, vector_unsigned_char) -> vector_unsigned_char } + impl_vec_trait!{ [$Trait $m] $sb (vector_signed_char, vector_signed_char) -> vector_signed_char } + impl_vec_trait!{ [$Trait $m] $uh (vector_unsigned_short, vector_unsigned_short) -> vector_unsigned_short } + impl_vec_trait!{ [$Trait $m] $sh (vector_signed_short, vector_signed_short) -> vector_signed_short } + impl_vec_trait!{ [$Trait $m] $uw (vector_unsigned_int, vector_unsigned_int) -> vector_unsigned_int } + impl_vec_trait!{ [$Trait $m] $sw (vector_signed_int, vector_signed_int) -> vector_signed_int } + }; + ([$Trait:ident $m:ident] 2 ($fn:ident)) => { + impl_vec_trait!{ [$Trait $m] ($fn, $fn, $fn, $fn, $fn, $fn) } + }; + ([$Trait:ident $m:ident]+ 2b ($b:ident, $h:ident, $w:ident)) => { + impl_vec_trait!{ [$Trait $m]+ $b (vector_bool_char, vector_bool_char) -> vector_bool_char } + impl_vec_trait!{ [$Trait $m]+ $b (vector_unsigned_char, vector_unsigned_char) -> vector_unsigned_char } + impl_vec_trait!{ [$Trait $m]+ $b (vector_signed_char, vector_signed_char) -> vector_signed_char } + impl_vec_trait!{ [$Trait $m]+ $h (vector_bool_short, vector_bool_short) -> vector_bool_short } + impl_vec_trait!{ [$Trait $m]+ $h (vector_unsigned_short, vector_unsigned_short) -> vector_unsigned_short } + impl_vec_trait!{ [$Trait $m]+ $h (vector_signed_short, vector_signed_short) -> vector_signed_short } + impl_vec_trait!{ [$Trait $m]+ $w (vector_bool_int, vector_bool_int) -> vector_bool_int } + impl_vec_trait!{ [$Trait $m]+ $w (vector_unsigned_int, vector_unsigned_int) -> vector_unsigned_int } + impl_vec_trait!{ [$Trait $m]+ $w (vector_signed_int, vector_signed_int) -> vector_signed_int } + }; + ([$Trait:ident $m:ident]+ 2b ($fn:ident)) => { + impl_vec_trait!{ [$Trait $m]+ 2b ($fn, $fn, $fn) } + }; +} + +macro_rules! s_t_l { + (i64x2) => { + vector_signed_long_long + }; + (i32x4) => { + vector_signed_int + }; + (i16x8) => { + vector_signed_short + }; + (i8x16) => { + vector_signed_char + }; + + (u64x2) => { + vector_unsigned_long_long + }; + (u32x4) => { + vector_unsigned_int + }; + (u16x8) => { + vector_unsigned_short + }; + (u8x16) => { + vector_unsigned_char + }; + + (f32x4) => { + vector_float + }; + (f64x2) => { + vector_double + }; +} + +macro_rules! t_t_l { + (i64) => { + vector_signed_long_long + }; + (i32) => { + vector_signed_int + }; + (i16) => { + vector_signed_short + }; + (i8) => { + vector_signed_char + }; + + (u64) => { + vector_unsigned_long_long + }; + (u32) => { + vector_unsigned_int + }; + (u16) => { + vector_unsigned_short + }; + (u8) => { + vector_unsigned_char + }; + + (f32) => { + vector_float + }; + (f64) => { + vector_double + }; +} + +macro_rules! t_t_s { + (i64) => { + i64x2 + }; + (i32) => { + i32x4 + }; + (i16) => { + i16x8 + }; + (i8) => { + i8x16 + }; + + (u64) => { + u64x2 + }; + (u32) => { + u32x4 + }; + (u16) => { + u16x8 + }; + (u8) => { + u8x16 + }; + + (f32) => { + f32x4 + }; + (f64) => { + f64x2 + }; +} + +macro_rules! t_u { + (vector_bool_char) => { + vector_unsigned_char + }; + (vector_bool_short) => { + vector_unsigned_short + }; + (vector_bool_int) => { + vector_unsigned_int + }; + (vector_unsigned_char) => { + vector_unsigned_char + }; + (vector_unsigned_short) => { + vector_unsigned_short + }; + (vector_unsigned_int) => { + vector_unsigned_int + }; + (vector_unsigned_long_long) => { + vector_unsigned_long_long + }; + (vector_signed_char) => { + vector_unsigned_char + }; + (vector_signed_short) => { + vector_unsigned_short + }; + (vector_signed_int) => { + vector_unsigned_int + }; + (vector_signed_long_long) => { + vector_signed_long_long + }; + (vector_float) => { + vector_unsigned_int + }; + (vector_double) => { + vector_unsigned_long_long + }; +} + +macro_rules! t_b { + (vector_bool_char) => { + vector_bool_char + }; + (vector_bool_short) => { + vector_bool_short + }; + (vector_bool_int) => { + vector_bool_int + }; + (vector_signed_char) => { + vector_bool_char + }; + (vector_signed_short) => { + vector_bool_short + }; + (vector_signed_int) => { + vector_bool_int + }; + (vector_signed_long_long) => { + vector_bool_long_long + }; + (vector_unsigned_char) => { + vector_bool_char + }; + (vector_unsigned_short) => { + vector_bool_short + }; + (vector_unsigned_int) => { + vector_bool_int + }; + (vector_unsigned_long_long) => { + vector_bool_long_long + }; + (vector_float) => { + vector_bool_int + }; + (vector_double) => { + vector_bool_long_long + }; +} + +macro_rules! impl_from { + ($s: ident) => { + #[unstable(feature = "stdarch_s390x", issue = "135681")] + impl From<$s> for s_t_l!($s) { + fn from (v: $s) -> Self { + unsafe { + transmute(v) + } + } + } + }; + ($($s: ident),*) => { + $( + impl_from! { $s } + )* + }; +} + +macro_rules! impl_neg { + ($s: ident : $zero: expr) => { + #[unstable(feature = "stdarch_s390x", issue = "135681")] + impl crate::ops::Neg for s_t_l!($s) { + type Output = s_t_l!($s); + fn neg(self) -> Self::Output { + let zero = $s::splat($zero); + unsafe { transmute(simd_sub(zero, transmute(self))) } + } + } + }; +} + +pub(crate) use impl_from; +pub(crate) use impl_neg; +pub(crate) use impl_vec_trait; +pub(crate) use s_t_l; +pub(crate) use t_b; +pub(crate) use t_t_l; +pub(crate) use t_t_s; +pub(crate) use t_u; +pub(crate) use test_impl; diff --git a/crates/core_arch/src/s390x/mod.rs b/crates/core_arch/src/s390x/mod.rs index 60996d6acc..7d3b3f2d99 100644 --- a/crates/core_arch/src/s390x/mod.rs +++ b/crates/core_arch/src/s390x/mod.rs @@ -1,4 +1,6 @@ -//! `SystemZ` intrinsics +//! `s390x` intrinsics + +pub(crate) mod macros; mod vector; #[unstable(feature = "stdarch_s390x", issue = "130869")] diff --git a/crates/core_arch/src/s390x/vector.rs b/crates/core_arch/src/s390x/vector.rs index e7f5c55ce7..5d50311b15 100644 --- a/crates/core_arch/src/s390x/vector.rs +++ b/crates/core_arch/src/s390x/vector.rs @@ -1,11 +1,161 @@ +//! s390x vector intrinsics. +//! +//! For more info see the [Reference Summary] or the online [IBM docs]. +//! +//! [Reference Summary]: https://www.ibm.com/support/pages/sites/default/files/2021-05/SA22-7871-10.pdf +//! [IBM docs]: https://www.ibm.com/docs/en/zos/2.4.0?topic=support-vector-built-in-functions + #![allow(non_camel_case_types)] -#![allow(unused_imports)] -use crate::{intrinsics::simd::*, mem::transmute}; +use crate::{core_arch::simd::*, intrinsics::simd::*, mem::transmute}; #[cfg(test)] use stdarch_test::assert_instr; +use super::macros::*; + +types! { + #![unstable(feature = "stdarch_s390x", issue = "135681")] + + /// s390x-specific 128-bit wide vector of sixteen packed `i8` + pub struct vector_signed_char(16 x i8); + /// s390x-specific 128-bit wide vector of sixteen packed `u8` + pub struct vector_unsigned_char(16 x u8); + /// s390x-specific 128-bit wide vector mask of sixteen packed elements + pub struct vector_bool_char(16 x i8); + + /// s390x-specific 128-bit wide vector of eight packed `i16` + pub struct vector_signed_short(8 x i16); + /// s390x-specific 128-bit wide vector of eight packed `u16` + pub struct vector_unsigned_short(8 x u16); + /// s390x-specific 128-bit wide vector mask of eight packed elements + pub struct vector_bool_short(8 x i16); + + /// s390x-specific 128-bit wide vector of four packed `i32` + pub struct vector_signed_int(4 x i32); + /// s390x-specific 128-bit wide vector of four packed `u32` + pub struct vector_unsigned_int(4 x u32); + /// s390x-specific 128-bit wide vector mask of four packed elements + pub struct vector_bool_int(4 x i32); + + /// s390x-specific 128-bit wide vector of two packed `i64` + pub struct vector_signed_long_long(2 x i64); + /// s390x-specific 128-bit wide vector of two packed `u64` + pub struct vector_unsigned_long_long(2 x u64); + /// s390x-specific 128-bit wide vector mask of two packed elements + pub struct vector_bool_long_long(2 x i64); + + /// s390x-specific 128-bit wide vector of four packed `f32` + pub struct vector_float(4 x f32); + /// s390x-specific 128-bit wide vector of two packed `f64` + pub struct vector_double(2 x f64); +} + +#[allow(improper_ctypes)] +extern "C" {} + +impl_from! { i8x16, u8x16, i16x8, u16x8, i32x4, u32x4, i64x2, u64x2, f32x4, f64x2 } + +impl_neg! { i8x16 : 0 } +impl_neg! { i16x8 : 0 } +impl_neg! { i32x4 : 0 } +impl_neg! { i64x2 : 0 } +impl_neg! { f32x4 : 0f32 } +impl_neg! { f64x2 : 0f64 } + +#[macro_use] +mod sealed { + use super::*; + + #[unstable(feature = "stdarch_s390x", issue = "135681")] + pub trait VectorAdd { + type Result; + unsafe fn vec_add(self, other: Other) -> Self::Result; + } + + macro_rules! impl_add { + ($name:ident, $a:ty, $instr:ident) => { + impl_add!($name, $a, $a, $a, $instr); + }; + ($name:ident, $a:ty, $b:ty, $c:ty, $instr:ident) => { + #[inline] + #[target_feature(enable = "vector")] + #[cfg_attr(test, assert_instr($instr))] + pub unsafe fn $name(a: $a, b: $b) -> $c { + transmute(simd_add(transmute(a), b)) + } + + #[unstable(feature = "stdarch_s390x", issue = "135681")] + impl VectorAdd<$b> for $a { + type Result = $c; + + #[inline] + #[target_feature(enable = "vector")] + unsafe fn vec_add(self, other: $b) -> Self::Result { + $name(self, other) + } + } + }; + } + + #[rustfmt::skip] + mod impl_add { + use super::*; + + impl_add!(va_sc, vector_signed_char, vab); + impl_add!(va_uc, vector_unsigned_char, vab); + impl_add!(va_sh, vector_signed_short, vah); + impl_add!(va_uh, vector_unsigned_short, vah); + impl_add!(va_sf, vector_signed_int, vaf); + impl_add!(va_uf, vector_unsigned_int, vaf); + impl_add!(va_sg, vector_signed_long_long, vag); + impl_add!(va_ug, vector_unsigned_long_long, vag); + + impl_add!(va_sc_bc, vector_signed_char, vector_bool_char, vector_signed_char, vab); + impl_add!(va_uc_bc, vector_unsigned_char, vector_bool_char, vector_unsigned_char, vab); + impl_add!(va_sh_bh, vector_signed_short, vector_bool_short, vector_signed_short, vah); + impl_add!(va_uh_bh, vector_unsigned_short, vector_bool_short, vector_unsigned_short, vah); + impl_add!(va_sf_bf, vector_signed_int, vector_bool_int, vector_signed_int, vaf); + impl_add!(va_uf_bf, vector_unsigned_int, vector_bool_int, vector_unsigned_int, vaf); + impl_add!(va_sg_bg, vector_signed_long_long, vector_bool_long_long, vector_signed_long_long, vag); + impl_add!(va_ug_bg, vector_unsigned_long_long, vector_bool_long_long, vector_unsigned_long_long, vag); + + impl_add!(va_bc_sc, vector_bool_char, vector_signed_char, vector_signed_char, vab); + impl_add!(va_bc_uc, vector_bool_char, vector_unsigned_char, vector_unsigned_char, vab); + impl_add!(va_bh_sh, vector_bool_short, vector_signed_short, vector_signed_short, vah); + impl_add!(va_bh_uh, vector_bool_short, vector_unsigned_short, vector_unsigned_short, vah); + impl_add!(va_bf_sf, vector_bool_int, vector_signed_int, vector_signed_int, vaf); + impl_add!(va_bf_uf, vector_bool_int, vector_unsigned_int, vector_unsigned_int, vaf); + impl_add!(va_bg_sg, vector_bool_long_long, vector_signed_long_long, vector_signed_long_long, vag); + impl_add!(va_bg_ug, vector_bool_long_long, vector_unsigned_long_long, vector_unsigned_long_long, vag); + + impl_add!(va_double, vector_double, vfadb); + + // FIXME: "vfasb" is part of vector enhancements 1, add a test for it when possible + #[unstable(feature = "stdarch_s390x", issue = "135681")] + impl VectorAdd for f32 { + type Result = Self; + + #[inline] + #[target_feature(enable = "vector")] + unsafe fn vec_add(self, other: Self) -> Self::Result { + simd_add(self, other) + } + } + } +} + +/// Vector add. +#[inline] +#[target_feature(enable = "vector")] +#[unstable(feature = "stdarch_s390x", issue = "135681")] +pub unsafe fn vec_add(a: T, b: U) -> >::Result +where + T: sealed::VectorAdd, +{ + a.vec_add(b) +} + #[cfg(test)] mod tests { use super::*; @@ -16,5 +166,12 @@ mod tests { use stdarch_test::simd_test; #[simd_test(enable = "vector")] - unsafe fn dummy() {} + unsafe fn vec_add_i32x4_i32x4() { + let x = i32x4::new(1, 2, 3, 4); + let y = i32x4::new(4, 3, 2, 1); + let x: vector_signed_int = transmute(x); + let y: vector_signed_int = transmute(y); + let z = vec_add(x, y); + assert_eq!(i32x4::splat(5), transmute(z)); + } }