Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement vec_perm #451

Merged
merged 11 commits into from
May 23, 2018
Merged
1 change: 1 addition & 0 deletions ci/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ case ${TARGET} in
;;
powerpc64-*)
export STDSIMD_DISABLE_ASSERT_INSTR=1
export STDSIMD_TEST_NORUN=1
;;

# On 32-bit use a static relocation model which avoids some extra
Expand Down
193 changes: 193 additions & 0 deletions coresimd/powerpc/altivec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@

use coresimd::simd::*;
use coresimd::simd_llvm::*;

use mem;

#[cfg(test)]
use stdsimd_test::assert_instr;

Expand Down Expand Up @@ -355,10 +358,55 @@ impl_from_bits_!(
vector_bool_int
);

#[allow(improper_ctypes)]
extern "C" {
#[ link_name = "llvm.ppc.altivec.vperm" ]
fn vperm(a: vector_signed_int, b: vector_signed_int, c: vector_unsigned_char) -> vector_signed_int;
#[ link_name = "llvm.ppc.altivec.vmhaddshs" ]
fn vmhaddshs(a: vector_signed_short, b: vector_signed_short, c: vector_signed_short) -> vector_signed_short;
}

mod sealed {

use super::*;

#[inline]
#[target_feature(enable = "altivec")]
#[cfg_attr(test, assert_instr(vperm))]
unsafe fn vec_vperm(a: vector_signed_int, b: vector_signed_int, c: vector_unsigned_char) -> vector_signed_int {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should add assert_instr tests for all vector types.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That function is the only one that is called for every vector type.

All the vector types are transmuted to i32x4.

vperm(a, b, c)
}

pub trait VectorPerm {
unsafe fn vec_vperm(self, b: Self, c: vector_unsigned_char) -> Self;
}

macro_rules! vector_perm {
{$impl: ident} => {
impl VectorPerm for $impl {
#[inline]
#[target_feature(enable = "altivec")]
unsafe fn vec_vperm(self, b: Self, c: vector_unsigned_char) -> Self {
mem::transmute(vec_vperm(mem::transmute(self), mem::transmute(b), c))
}
}
}
}

vector_perm!{ vector_signed_char }
vector_perm!{ vector_unsigned_char }
vector_perm!{ vector_bool_char }

vector_perm!{ vector_signed_short }
vector_perm!{ vector_unsigned_short }
vector_perm!{ vector_bool_short }

vector_perm!{ vector_signed_int }
vector_perm!{ vector_unsigned_int }
vector_perm!{ vector_bool_int }

vector_perm!{ vector_float }

pub trait VectorAdd<Other> {
type Result;
unsafe fn vec_add(self, other: Other) -> Self::Result;
Expand Down Expand Up @@ -655,6 +703,53 @@ where
a.vec_add(b)
}


/// Endian-biased intrinsics
#[cfg(target_endian = "little")]
mod endian {
use super::*;
/// Vector permute.
#[inline]
#[target_feature(enable = "altivec")]
pub unsafe fn vec_perm<T>(a: T, b: T, c: vector_unsigned_char) -> T
where
T: sealed::VectorPerm,
{
// vperm has big-endian bias
//
// Xor the mask and flip the arguments
let d = u8x16::new(255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255).into_bits();
let c = simd_xor(c, d);

b.vec_vperm(a, c)
}
}

/// Vector Multiply Add Saturated
#[inline]
#[target_feature(enable = "altivec")]
#[cfg_attr(test, assert_instr(vmhaddshs))]
pub unsafe fn vec_madds(a: vector_signed_short, b: vector_signed_short, c: vector_signed_short) -> vector_signed_short {
vmhaddshs(a, b, c)
}

#[cfg(target_endian = "big")]
mod endian {
use super::*;
/// Vector permute.
#[inline]
#[target_feature(enable = "altivec")]
pub unsafe fn vec_perm<T>(a: T, b: T, c: vector_unsigned_char) -> T
where
T: sealed::VectorPerm,
{
a.vec_vperm(b, c)
}
}

pub use self::endian::*;

#[cfg(test)]
mod tests {
#[cfg(target_arch = "powerpc")]
Expand All @@ -666,6 +761,104 @@ mod tests {
use simd::*;
use stdsimd_test::simd_test;

macro_rules! test_vec_perm {
{$name:ident, $shorttype:ident, $longtype:ident, [$($a:expr),+], [$($b:expr),+], [$($c:expr),+], [$($d:expr),+]} => {
#[simd_test(enable = "altivec")]
unsafe fn $name() {
let a: $longtype = $shorttype::new($($a),+).into_bits();
let b = $shorttype::new($($b),+).into_bits();
let c = u8x16::new($($c),+).into_bits();
let d = $shorttype::new($($d),+);

assert_eq!(d, vec_perm(a, b, c).into_bits());
}
}
}

test_vec_perm!{test_vec_perm_u8x16,
u8x16, vector_unsigned_char,
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
[100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115],
[0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13,
0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17],
[0, 1, 100, 101, 2, 3, 102, 103, 4, 5, 104, 105, 6, 7, 106, 107]}
test_vec_perm!{test_vec_perm_i8x16,
i8x16, vector_signed_char,
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
[100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115],
[0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13,
0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17],
[0, 1, 100, 101, 2, 3, 102, 103, 4, 5, 104, 105, 6, 7, 106, 107]}
test_vec_perm!{test_vec_perm_m8x16,
m8x16, vector_bool_char,
[false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false],
[true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true],
[0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13,
0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17],
[false, false, true, true, false, false, true, true, false, false, true, true, false, false, true, true]}

test_vec_perm!{test_vec_perm_u16x8,
u16x8, vector_unsigned_short,
[0, 1, 2, 3, 4, 5, 6, 7],
[10, 11, 12, 13, 14, 15, 16, 17],
[0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13,
0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17],
[0, 10, 1, 11, 2, 12, 3, 13]}
test_vec_perm!{test_vec_perm_i16x8,
i16x8, vector_signed_short,
[0, 1, 2, 3, 4, 5, 6, 7],
[10, 11, 12, 13, 14, 15, 16, 17],
[0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13,
0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17],
[0, 10, 1, 11, 2, 12, 3, 13]}
test_vec_perm!{test_vec_perm_m16x8,
m16x8, vector_bool_short,
[false, false, false, false, false, false, false, false],
[true, true, true, true, true, true, true, true],
[0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13,
0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17],
[false, true, false, true, false, true, false, true]}

test_vec_perm!{test_vec_perm_u32x4,
u32x4, vector_unsigned_int,
[0, 1, 2, 3],
[10, 11, 12, 13],
[0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13,
0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17],
[0, 10, 1, 11]}
test_vec_perm!{test_vec_perm_i32x4,
i32x4, vector_signed_int,
[0, 1, 2, 3],
[10, 11, 12, 13],
[0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13,
0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17],
[0, 10, 1, 11]}
test_vec_perm!{test_vec_perm_m32x4,
m32x4, vector_bool_int,
[false, false, false, false],
[true, true, true, true],
[0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13,
0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17],
[false, true, false, true]}
test_vec_perm!{test_vec_perm_f32x4,
f32x4, vector_float,
[0.0, 1.0, 2.0, 3.0],
[1.0, 1.1, 1.2, 1.3],
[0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13,
0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17],
[0.0, 1.0, 1.0, 1.1]}

#[simd_test(enable = "altivec")]
unsafe fn test_vec_madds() {
let a: vector_signed_short = i16x8::new(0 * 256, 1 * 256, 2 * 256, 3 * 256, 4 * 256, 5 * 256, 6 * 256, 7 * 256).into_bits();
let b: vector_signed_short = i16x8::new(256, 256, 256, 256, 256, 256, 256, 256).into_bits();
let c: vector_signed_short = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7).into_bits();

let d = i16x8::new(0, 3, 6, 9, 12, 15, 18, 21);

assert_eq!(d, vec_madds(a, b, c).into_bits());
}

#[simd_test(enable = "altivec")]
unsafe fn vec_add_i32x4_i32x4() {
let x = i32x4::new(1, 2, 3, 4);
Expand Down
89 changes: 89 additions & 0 deletions coresimd/powerpc64/vsx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@

use coresimd::powerpc::*;
use coresimd::simd::*;
use coresimd::simd_llvm::*;

#[cfg(test)]
use stdsimd_test::assert_instr;

use mem;

types! {
// pub struct vector_Float16 = f16x8;
Expand Down Expand Up @@ -216,3 +222,86 @@ impl_from_bits_!(
vector_bool_long,
vector_double
);

mod sealed {

use super::*;

pub trait VectorPermDI {
unsafe fn vec_xxpermdi(self, b: Self, dm: u8) -> Self;
}

// xxpermdi has an big-endian bias and extended mnemonics
#[inline]
#[target_feature(enable = "vsx")]
#[cfg_attr(all(test, target_endian="little"), assert_instr(xxmrgld, dm = 0x0))]
#[cfg_attr(all(test, target_endian="big"), assert_instr(xxspltd, dm = 0x0))]
unsafe fn xxpermdi(a: i64x2, b: i64x2, dm: u8) -> i64x2 {
match dm & 0b11 {
0 => simd_shuffle2(a, b, [0b00, 0b10]),
1 => simd_shuffle2(a, b, [0b01, 0b10]),
2 => simd_shuffle2(a, b, [0b00, 0b11]),
_ => simd_shuffle2(a, b, [0b01, 0b11]),
}
}

macro_rules! vec_xxpermdi {
{$impl: ident} => {
impl VectorPermDI for $impl {
#[inline]
#[target_feature(enable = "vsx")]
unsafe fn vec_xxpermdi(self, b: Self, dm: u8) -> Self {
mem::transmute(xxpermdi(mem::transmute(self), mem::transmute(b), dm))
}
}
}
}

vec_xxpermdi! { vector_unsigned_long }
vec_xxpermdi! { vector_signed_long }
vec_xxpermdi! { vector_bool_long }
vec_xxpermdi! { vector_double }
}

/// Vector permute.
#[inline]
#[target_feature(enable = "vsx")]
#[rustc_args_required_const(2)]
pub unsafe fn vec_xxpermdi<T>(a: T, b: T, dm: u8) -> T
where
T: sealed::VectorPermDI,
{
a.vec_xxpermdi(b, dm)
}

#[cfg(test)]
mod tests {
#[cfg(target_arch = "powerpc")]
use coresimd::arch::powerpc::*;

#[cfg(target_arch = "powerpc64")]
use coresimd::arch::powerpc64::*;

use simd::*;
use stdsimd_test::simd_test;

macro_rules! test_vec_xxpermdi {
{$name:ident, $shorttype:ident, $longtype:ident, [$($a:expr),+], [$($b:expr),+], [$($c:expr),+], [$($d:expr),+]} => {
#[simd_test(enable = "vsx")]
unsafe fn $name() {
let a: $longtype = $shorttype::new($($a),+, $($b),+).into_bits();
let b = $shorttype::new($($c),+, $($d),+).into_bits();

assert_eq!($shorttype::new($($a),+, $($c),+), vec_xxpermdi(a, b, 0).into_bits());
assert_eq!($shorttype::new($($b),+, $($c),+), vec_xxpermdi(a, b, 1).into_bits());
assert_eq!($shorttype::new($($a),+, $($d),+), vec_xxpermdi(a, b, 2).into_bits());
assert_eq!($shorttype::new($($b),+, $($d),+), vec_xxpermdi(a, b, 3).into_bits());
}
}
}

test_vec_xxpermdi!{test_vec_xxpermdi_u64x2, u64x2, vector_unsigned_long, [0], [1], [2], [3]}
test_vec_xxpermdi!{test_vec_xxpermdi_i64x2, i64x2, vector_signed_long, [0], [-1], [2], [-3]}
test_vec_xxpermdi!{test_vec_xxpermdi_m64x2, m64x2, vector_bool_long, [false], [true], [false], [true]}
test_vec_xxpermdi!{test_vec_xxpermdi_f64x2, f64x2, vector_double, [0.0], [1.0], [2.0], [3.0]}
}
8 changes: 8 additions & 0 deletions crates/simd-test-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,18 @@ pub fn simd_test(
let q = quote!{ true };
q.to_tokens(&mut cfg_target_features);

let test_norun = std::env::var("STDSIMD_TEST_NORUN").is_ok();
let maybe_ignore = if !test_norun {
TokenStream::empty()
} else {
(quote! { #[ignore] }).into()
};

let ret: TokenStream = quote_spanned! {
proc_macro2::Span::call_site() =>
#[allow(non_snake_case)]
#[test]
#maybe_ignore
fn #name() {
if #force_test | (#cfg_target_features) {
return unsafe { #name() };
Expand Down
2 changes: 1 addition & 1 deletion crates/stdsimd-test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ simd-test-macro = { path = "../simd-test-macro" }
backtrace = "0.3"
cc = "1.0"
lazy_static = "0.2"
rustc-demangle = "0.1"
rustc-demangle = "0.1.8"