Skip to content

Commit bab4baa

Browse files
committed
PowerPC: Implement vec_cmp for VSX vector float/double
Implements VSX floating-point comparison intrinsics for PowerPC. Add support for vec_cmpeq, vec_cmpgt, and vec_cmpge operations on vector_float and vector_double types. Implementation uses VSX-specific instructions (xvcmpeqsp/xvcmpeqdp, xvcmpgtsp/xvcmpgtdp, xvcmpgesp/xvcmpgedp) for improved performance when VSX is available, while maintaining backward compatibility with AltiVec's vcmpgefp for vector_float when VSX is not enabled. AI Assited.
1 parent 6332f19 commit bab4baa

2 files changed

Lines changed: 178 additions & 3 deletions

File tree

crates/core_arch/src/powerpc/altivec.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ unsafe extern "unadjusted" {
411411
}
412412

413413
#[macro_use]
414-
mod sealed {
414+
pub(crate) mod sealed {
415415
use super::*;
416416

417417
#[unstable(feature = "stdarch_powerpc", issue = "111145")]
@@ -836,8 +836,27 @@ mod sealed {
836836

837837
impl_vec_cmp! { [VectorCmpGt vec_cmpgt] ( vec_vcmpgtub, vec_vcmpgtsb, vec_vcmpgtuh, vec_vcmpgtsh, vec_vcmpgtuw, vec_vcmpgtsw ) }
838838

839+
#[unstable(feature = "stdarch_powerpc", issue = "111145")]
840+
pub trait VectorCmpGe<Other> {
841+
type Result;
842+
unsafe fn vec_cmpge(self, b: Other) -> Self::Result;
843+
}
844+
839845
test_impl! { vec_vcmpgefp(a: vector_float, b: vector_float) -> vector_bool_int [ vcmpgefp, vcmpgefp ] }
840846

847+
// Implement VectorCmpGe trait for vector_float using vcmpgefp (AltiVec)
848+
// This is overridden by vsx.rs when VSX is available
849+
#[cfg(not(target_feature = "vsx"))]
850+
#[unstable(feature = "stdarch_powerpc", issue = "111145")]
851+
impl VectorCmpGe<vector_float> for vector_float {
852+
type Result = vector_bool_int;
853+
#[inline]
854+
#[target_feature(enable = "altivec")]
855+
unsafe fn vec_cmpge(self, b: vector_float) -> Self::Result {
856+
vec_vcmpgefp(self, b)
857+
}
858+
}
859+
841860
test_impl! { vec_vcmpequb(a: vector_unsigned_char, b: vector_unsigned_char) -> vector_bool_char [ vcmpequb, vcmpequb ] }
842861
test_impl! { vec_vcmpequh(a: vector_unsigned_short, b: vector_unsigned_short) -> vector_bool_short [ vcmpequh, vcmpequh ] }
843862
test_impl! { vec_vcmpequw(a: vector_unsigned_int, b: vector_unsigned_int) -> vector_bool_int [ vcmpequw, vcmpequw ] }
@@ -3779,8 +3798,11 @@ where
37793798
#[inline]
37803799
#[target_feature(enable = "altivec")]
37813800
#[unstable(feature = "stdarch_powerpc", issue = "111145")]
3782-
pub unsafe fn vec_cmpge(a: vector_float, b: vector_float) -> vector_bool_int {
3783-
sealed::vec_vcmpgefp(a, b)
3801+
pub unsafe fn vec_cmpge<T, U>(a: T, b: U) -> <T as sealed::VectorCmpGe<U>>::Result
3802+
where
3803+
T: sealed::VectorCmpGe<U>,
3804+
{
3805+
a.vec_cmpge(b)
37843806
}
37853807

37863808
/// Vector cmpeq.

crates/core_arch/src/powerpc/vsx.rs

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
use crate::core_arch::powerpc::*;
1212
use crate::core_arch::simd::*;
13+
use crate::intrinsics::simd::*;
1314

1415
#[cfg(test)]
1516
use stdarch_test::assert_instr;
@@ -173,6 +174,64 @@ mod sealed {
173174
vec_mergeeo! { vector_float, mergee, mergeo }
174175
}
175176

177+
// Macro to implement VectorCmpEq trait for vector types.
178+
macro_rules! impl_vec_cmpeq {
179+
($vec_ty:ident, $result_ty:ident, $mask_ty:ident, $instr:ident) => {
180+
#[unstable(feature = "stdarch_powerpc", issue = "111145")]
181+
impl crate::core_arch::powerpc::altivec::sealed::VectorCmpEq<$vec_ty> for $vec_ty {
182+
type Result = $result_ty;
183+
#[inline]
184+
#[target_feature(enable = "vsx")]
185+
#[cfg_attr(test, assert_instr($instr))]
186+
unsafe fn vec_cmpeq(self, b: $vec_ty) -> Self::Result {
187+
let result: $mask_ty = simd_eq(self, b);
188+
transmute(result)
189+
}
190+
}
191+
};
192+
}
193+
impl_vec_cmpeq!(vector_float, vector_bool_int, m32x4, xvcmpeqsp);
194+
impl_vec_cmpeq!(vector_double, vector_bool_long, m64x2, xvcmpeqdp);
195+
196+
// Macro to implement VectorCmpGt trait for vector types.
197+
macro_rules! impl_vec_cmpgt {
198+
($vec_ty:ident, $result_ty:ident, $mask_ty:ident, $instr:ident) => {
199+
#[unstable(feature = "stdarch_powerpc", issue = "111145")]
200+
impl crate::core_arch::powerpc::altivec::sealed::VectorCmpGt<$vec_ty> for $vec_ty {
201+
type Result = $result_ty;
202+
#[inline]
203+
#[target_feature(enable = "vsx")]
204+
#[cfg_attr(test, assert_instr($instr))]
205+
unsafe fn vec_cmpgt(self, b: $vec_ty) -> Self::Result {
206+
let result: $mask_ty = simd_gt(self, b);
207+
transmute(result)
208+
}
209+
}
210+
};
211+
}
212+
impl_vec_cmpgt!(vector_float, vector_bool_int, m32x4, xvcmpgtsp);
213+
impl_vec_cmpgt!(vector_double, vector_bool_long, m64x2, xvcmpgtdp);
214+
215+
// Macro to implement VectorCmpGe trait for vector types.
216+
macro_rules! impl_vec_cmpge {
217+
($vec_ty:ident, $result_ty:ident, $mask_ty:ident, $instr:ident) => {
218+
#[cfg(target_feature = "vsx")]
219+
#[unstable(feature = "stdarch_powerpc", issue = "111145")]
220+
impl crate::core_arch::powerpc::altivec::sealed::VectorCmpGe<$vec_ty> for $vec_ty {
221+
type Result = $result_ty;
222+
#[inline]
223+
#[target_feature(enable = "vsx")]
224+
#[cfg_attr(test, assert_instr($instr))]
225+
unsafe fn vec_cmpge(self, b: $vec_ty) -> Self::Result {
226+
let result: $mask_ty = simd_ge(self, b);
227+
transmute(result)
228+
}
229+
}
230+
};
231+
}
232+
impl_vec_cmpge!(vector_float, vector_bool_int, m32x4, xvcmpgesp);
233+
impl_vec_cmpge!(vector_double, vector_bool_long, m64x2, xvcmpgedp);
234+
176235
/// Vector permute.
177236
#[inline]
178237
#[target_feature(enable = "vsx")]
@@ -255,4 +314,98 @@ mod tests {
255314
test_vec_xxpermdi! {test_vec_xxpermdi_i64x2, i64x2, vector_signed_long, [0], [-1], [2], [-3]}
256315
test_vec_xxpermdi! {test_vec_xxpermdi_m64x2, m64x2, vector_bool_long, [false], [true], [false], [true]}
257316
test_vec_xxpermdi! {test_vec_xxpermdi_f64x2, f64x2, vector_double, [0.0], [1.0], [2.0], [3.0]}
317+
318+
#[simd_test(enable = "vsx")]
319+
fn test_vec_cmpeq_f32x4() {
320+
let a = vector_float::from(f32x4::from_array([1.0, 2.0, 3.0, 4.0]));
321+
let b = vector_float::from(f32x4::from_array([1.0, 3.0, 3.0, 5.0]));
322+
323+
unsafe {
324+
let result: vector_bool_int = vec_cmpeq(a, b);
325+
// Elements 0 and 2 are equal, elements 1 and 3 are not equal.
326+
// Equal elements should have all bits set (-1), non-equal should be 0.
327+
let result_i32: i32x4 = transmute(result);
328+
assert_eq!(result_i32.as_array()[0], -1i32);
329+
assert_eq!(result_i32.as_array()[1], 0i32);
330+
assert_eq!(result_i32.as_array()[2], -1i32);
331+
assert_eq!(result_i32.as_array()[3], 0i32);
332+
}
333+
}
334+
335+
#[simd_test(enable = "vsx")]
336+
fn test_vec_cmpeq_f64x2() {
337+
let a = vector_double::from(f64x2::from_array([1.0, 2.0]));
338+
let b = vector_double::from(f64x2::from_array([1.0, 3.0]));
339+
340+
unsafe {
341+
let result: vector_bool_long = vec_cmpeq(a, b);
342+
// First element equal (1.0 == 1.0), second not equal (2.0 != 3.0).
343+
// Equal elements should have all bits set (-1), non-equal should be 0.
344+
let result_i64: i64x2 = transmute(result);
345+
assert_eq!(result_i64.as_array()[0], -1i64);
346+
assert_eq!(result_i64.as_array()[1], 0i64);
347+
}
348+
}
349+
350+
#[simd_test(enable = "vsx")]
351+
fn test_vec_cmpgt_f32x4() {
352+
let a = vector_float::from(f32x4::from_array([1.0, 2.0, 3.0, 4.0]));
353+
let b = vector_float::from(f32x4::from_array([0.0, 3.0, 3.0, 5.0]));
354+
355+
unsafe {
356+
let result: vector_bool_int = vec_cmpgt(a, b);
357+
// Element 0: 1.0 > 0.0 (true), Element 1: 2.0 > 3.0 (false)
358+
// Element 2: 3.0 > 3.0 (false), Element 3: 4.0 > 5.0 (false)
359+
let result_i32: i32x4 = transmute(result);
360+
assert_eq!(result_i32.as_array()[0], -1i32);
361+
assert_eq!(result_i32.as_array()[1], 0i32);
362+
assert_eq!(result_i32.as_array()[2], 0i32);
363+
assert_eq!(result_i32.as_array()[3], 0i32);
364+
}
365+
}
366+
367+
#[simd_test(enable = "vsx")]
368+
fn test_vec_cmpgt_f64x2() {
369+
let a = vector_double::from(f64x2::from_array([2.0, 1.0]));
370+
let b = vector_double::from(f64x2::from_array([1.0, 3.0]));
371+
372+
unsafe {
373+
let result: vector_bool_long = vec_cmpgt(a, b);
374+
// First element: 2.0 > 1.0 (true), second: 1.0 > 3.0 (false)
375+
let result_i64: i64x2 = transmute(result);
376+
assert_eq!(result_i64.as_array()[0], -1i64);
377+
assert_eq!(result_i64.as_array()[1], 0i64);
378+
}
379+
}
380+
381+
#[simd_test(enable = "vsx")]
382+
fn test_vec_cmpge_f32x4() {
383+
let a = vector_float::from(f32x4::from_array([1.0, 2.0, 3.0, 4.0]));
384+
let b = vector_float::from(f32x4::from_array([0.0, 3.0, 3.0, 5.0]));
385+
386+
unsafe {
387+
let result: vector_bool_int = vec_cmpge(a, b);
388+
// Element 0: 1.0 >= 0.0 (true), Element 1: 2.0 >= 3.0 (false)
389+
// Element 2: 3.0 >= 3.0 (true), Element 3: 4.0 >= 5.0 (false)
390+
let result_i32: i32x4 = transmute(result);
391+
assert_eq!(result_i32.as_array()[0], -1i32);
392+
assert_eq!(result_i32.as_array()[1], 0i32);
393+
assert_eq!(result_i32.as_array()[2], -1i32);
394+
assert_eq!(result_i32.as_array()[3], 0i32);
395+
}
396+
}
397+
398+
#[simd_test(enable = "vsx")]
399+
fn test_vec_cmpge_f64x2() {
400+
let a = vector_double::from(f64x2::from_array([2.0, 3.0]));
401+
let b = vector_double::from(f64x2::from_array([1.0, 3.0]));
402+
403+
unsafe {
404+
let result: vector_bool_long = vec_cmpge(a, b);
405+
// First element: 2.0 >= 1.0 (true), second: 3.0 >= 3.0 (true)
406+
let result_i64: i64x2 = transmute(result);
407+
assert_eq!(result_i64.as_array()[0], -1i64);
408+
assert_eq!(result_i64.as_array()[1], -1i64);
409+
}
410+
}
258411
}

0 commit comments

Comments
 (0)