Skip to content

Commit 410cd80

Browse files
gnzlbgalexcrichton
authored andcommitted
implement vertical min/max ops (rust-lang#418)
1 parent 8448a0f commit 410cd80

File tree

3 files changed

+164
-3
lines changed

3 files changed

+164
-3
lines changed

coresimd/ppsv/api/minmax.rs

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
//! Lane-wise arithmetic operations.
2+
#![allow(unused)]
3+
4+
macro_rules! impl_int_minmax_ops {
5+
($id:ident) => {
6+
impl $id {
7+
// Note:
8+
//
9+
// * if two elements are equal min returns
10+
// always the second element
11+
// * if two elements are equal max returns
12+
// always the second element
13+
//
14+
// Since we are dealing with integers here, and `min` and `max`
15+
// construct a new integer vector, whether the first or the
16+
// second element is returned when two elements compare equal
17+
// does not matter.
18+
19+
/// Minimum of two vectors.
20+
///
21+
/// Returns a new vector containing the minimum value of each of
22+
/// the input vector lanes.
23+
#[inline]
24+
pub fn min(self, x: Self) -> Self {
25+
self.lt(x).select(self, x)
26+
}
27+
28+
/// Maximum of two vectors.
29+
///
30+
/// Returns a new vector containing the minimum value of each of
31+
/// the input vector lanes.
32+
#[inline]
33+
pub fn max(self, x: Self) -> Self {
34+
self.gt(x).select(self, x)
35+
}
36+
}
37+
};
38+
}
39+
40+
#[cfg(test)]
41+
macro_rules! test_int_minmax_ops {
42+
($id:ident, $elem_ty:ident) => {
43+
#[test]
44+
fn minmax() {
45+
use coresimd::simd::$id;
46+
let o = $id::splat(1 as $elem_ty);
47+
let t = $id::splat(2 as $elem_ty);
48+
49+
let mut m = o;
50+
for i in 0..$id::lanes() {
51+
if i % 2 == 0 {
52+
m = m.replace(i, 2 as $elem_ty);
53+
}
54+
}
55+
56+
assert_eq!(o.min(t), o);
57+
assert_eq!(t.min(o), o);
58+
assert_eq!(m.min(o), o);
59+
assert_eq!(o.min(m), o);
60+
assert_eq!(m.min(t), m);
61+
assert_eq!(t.min(m), m);
62+
63+
assert_eq!(o.max(t), t);
64+
assert_eq!(t.max(o), t);
65+
assert_eq!(m.max(o), m);
66+
assert_eq!(o.max(m), m);
67+
assert_eq!(m.max(t), t);
68+
assert_eq!(t.max(m), t);
69+
}
70+
};
71+
}
72+
73+
macro_rules! impl_float_minmax_ops {
74+
($id:ident) => {
75+
impl $id {
76+
/// Minimum of two vectors.
77+
///
78+
/// Returns a new vector containing the minimum value of each of the
79+
/// input vector lanes. The lane-wise semantics are the same as that
80+
/// of `min` for the primitive floating-point types.
81+
#[inline]
82+
pub fn min(self, x: Self) -> Self {
83+
use coresimd::simd_llvm::simd_fmin;
84+
unsafe { simd_fmin(self, x) }
85+
}
86+
87+
/// Maximum of two vectors.
88+
///
89+
/// Returns a new vector containing the minimum value of each of the
90+
/// input vector lanes. The lane-wise semantics are the same as that
91+
/// of `max` for the primitive floating-point types.
92+
#[inline]
93+
pub fn max(self, x: Self) -> Self {
94+
// FIXME: https://github.com/rust-lang-nursery/stdsimd/issues/416
95+
// use coresimd::simd_llvm::simd_fmax;
96+
// unsafe { simd_fmax(self, x) }
97+
use num::Float;
98+
let mut r = self;
99+
for i in 0..$id::lanes() {
100+
let a = self.extract(i);
101+
let b = x.extract(i);
102+
r = r.replace(i, a.max(b))
103+
}
104+
r
105+
}
106+
}
107+
}
108+
}
109+
110+
#[cfg(test)]
111+
macro_rules! test_float_minmax_ops {
112+
($id:ident, $elem_ty:ident) => {
113+
#[test]
114+
fn minmax() {
115+
use coresimd::simd::$id;
116+
let n = ::std::$elem_ty::NAN;
117+
let o = $id::splat(1. as $elem_ty);
118+
let t = $id::splat(2. as $elem_ty);
119+
120+
let mut m = o;
121+
let mut on = o;
122+
for i in 0..$id::lanes() {
123+
if i % 2 == 0 {
124+
m = m.replace(i, 2. as $elem_ty);
125+
on = on.replace(i, n);
126+
}
127+
}
128+
129+
assert_eq!(o.min(t), o);
130+
assert_eq!(t.min(o), o);
131+
assert_eq!(m.min(o), o);
132+
assert_eq!(o.min(m), o);
133+
assert_eq!(m.min(t), m);
134+
assert_eq!(t.min(m), m);
135+
136+
assert_eq!(o.max(t), t);
137+
assert_eq!(t.max(o), t);
138+
assert_eq!(m.max(o), m);
139+
assert_eq!(o.max(m), m);
140+
assert_eq!(m.max(t), t);
141+
assert_eq!(t.max(m), t);
142+
143+
assert_eq!(on.min(o), o);
144+
assert_eq!(o.min(on), o);
145+
assert_eq!(on.max(o), o);
146+
assert_eq!(o.max(on), o);
147+
}
148+
};
149+
}

coresimd/ppsv/api/mod.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ mod masks_reductions;
100100
#[macro_use]
101101
mod minimal;
102102
#[macro_use]
103+
mod minmax;
104+
#[macro_use]
103105
mod minmax_reductions;
104106
#[macro_use]
105107
mod neg;
@@ -139,7 +141,8 @@ macro_rules! simd_f_ty {
139141
[impl_minmax_reductions, $id, $elem_ty],
140142
[impl_neg_op, $id, $elem_ty],
141143
[impl_partial_eq, $id],
142-
[impl_default, $id, $elem_ty]
144+
[impl_default, $id, $elem_ty],
145+
[impl_float_minmax_ops, $id]
143146
);
144147

145148
$test_macro!(
@@ -156,6 +159,7 @@ macro_rules! simd_f_ty {
156159
test_partial_eq!($id, 1. as $elem_ty, 0. as $elem_ty);
157160
test_default!($id, $elem_ty);
158161
test_mask_select!($mask_ty, $id, $elem_ty);
162+
test_float_minmax_ops!($id, $elem_ty);
159163
}
160164
);
161165
}
@@ -184,7 +188,8 @@ macro_rules! simd_i_ty {
184188
[impl_hex_fmt, $id, $elem_ty],
185189
[impl_eq, $id],
186190
[impl_partial_eq, $id],
187-
[impl_default, $id, $elem_ty]
191+
[impl_default, $id, $elem_ty],
192+
[impl_int_minmax_ops, $id]
188193
);
189194

190195
$test_macro!(
@@ -208,6 +213,7 @@ macro_rules! simd_i_ty {
208213
test_partial_eq!($id, 1 as $elem_ty, 0 as $elem_ty);
209214
test_default!($id, $elem_ty);
210215
test_mask_select!($mask_ty, $id, $elem_ty);
216+
test_int_minmax_ops!($id, $elem_ty);
211217
}
212218
);
213219
}
@@ -235,7 +241,8 @@ macro_rules! simd_u_ty {
235241
[impl_hex_fmt, $id, $elem_ty],
236242
[impl_eq, $id],
237243
[impl_partial_eq, $id],
238-
[impl_default, $id, $elem_ty]
244+
[impl_default, $id, $elem_ty],
245+
[impl_int_minmax_ops, $id]
239246
);
240247

241248
$test_macro!(
@@ -258,6 +265,7 @@ macro_rules! simd_u_ty {
258265
test_partial_eq!($id, 1 as $elem_ty, 0 as $elem_ty);
259266
test_default!($id, $elem_ty);
260267
test_mask_select!($mask_ty, $id, $elem_ty);
268+
test_int_minmax_ops!($id, $elem_ty);
261269
}
262270
);
263271
}

coresimd/simd_llvm.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,8 @@ extern "platform-intrinsic" {
4747
pub fn simd_reduce_any<T>(x: T) -> bool;
4848

4949
pub fn simd_select<M, T>(m: M, a: T, b: T) -> T;
50+
51+
pub fn simd_fmin<T>(a: T, b: T) -> T;
52+
// FIXME: https://github.com/rust-lang-nursery/stdsimd/issues/416
53+
// pub fn simd_fmax<T>(a: T, b: T) -> T;
5054
}

0 commit comments

Comments
 (0)