Skip to content

Commit c6b3f68

Browse files
committed
Auto merge of #1991 - RalfJung:rustup, r=RalfJung
Rustup: simd_select Cc rust-lang/rust#94474
2 parents e05a543 + 363236e commit c6b3f68

File tree

4 files changed

+55
-23
lines changed

4 files changed

+55
-23
lines changed

rust-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
6a705566166debf5eff88c57140df607fa409aaa
1+
f0c4da49983aa699f715caf681e3154b445fb60b

src/helpers.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,3 +758,18 @@ pub fn immty_from_uint_checked<'tcx>(
758758
err_unsup_format!("unsigned value {:#x} does not fit in {} bits", int, layout.size.bits())
759759
})?)
760760
}
761+
762+
pub fn bool_to_simd_element(b: bool, size: Size) -> Scalar<Tag> {
763+
// SIMD uses all-1 as pattern for "true"
764+
let val = if b { -1 } else { 0 };
765+
Scalar::from_int(val, size)
766+
}
767+
768+
pub fn simd_element_to_bool<'tcx>(elem: ImmTy<'tcx, Tag>) -> InterpResult<'tcx, bool> {
769+
let val = elem.to_scalar()?.to_int(elem.layout.size)?;
770+
Ok(match val {
771+
0 => false,
772+
-1 => true,
773+
_ => throw_ub_format!("each element of a SIMD mask must be all-0-bits or all-1-bits"),
774+
})
775+
}

src/shims/intrinsics.rs

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_middle::{mir, mir::BinOp, ty, ty::FloatTy};
88
use rustc_target::abi::{Align, Integer};
99

1010
use crate::*;
11-
use helpers::check_arg_count;
11+
use helpers::{bool_to_simd_element, check_arg_count, simd_element_to_bool};
1212

1313
pub enum AtomicOp {
1414
MirOp(mir::BinOp, bool),
@@ -365,8 +365,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
365365
// Special handling for boolean-returning operations
366366
assert_eq!(ty, this.tcx.types.bool);
367367
let val = val.to_bool().unwrap();
368-
let val = if val { -1 } else { 0 }; // SIMD uses all-1 as pattern for "true"
369-
let val = Scalar::from_int(val, dest.layout.size);
368+
let val = bool_to_simd_element(val, dest.layout.size);
370369
this.write_scalar(val, &dest.into())?;
371370
} else {
372371
assert_eq!(ty, dest.layout.ty);
@@ -381,21 +380,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
381380
let mut res = false; // the neutral element
382381
for i in 0..arg_len {
383382
let op = this.read_immediate(&this.mplace_index(&arg, i)?.into())?;
384-
// We convert it to a *signed* integer and expect either 0 or -1 (the latter means all bits were set).
385-
let val = op.to_scalar()?.to_int(op.layout.size)?;
386-
let val = match val {
387-
0 => false,
388-
-1 => true,
389-
_ =>
390-
throw_ub_format!(
391-
"each element of a simd_reduce_any operand must be all-0-bits or all-1-bits"
392-
),
393-
};
383+
let val = simd_element_to_bool(op)?;
394384
res = res | val;
395385
}
396386

397387
this.write_scalar(Scalar::from_bool(res), dest)?;
398388
}
389+
"simd_select" => {
390+
let &[ref mask, ref yes, ref no] = check_arg_count(args)?;
391+
let (mask, mask_len) = this.operand_to_simd(mask)?;
392+
let (yes, yes_len) = this.operand_to_simd(yes)?;
393+
let (no, no_len) = this.operand_to_simd(no)?;
394+
let (dest, dest_len) = this.place_to_simd(dest)?;
395+
396+
assert_eq!(dest_len, mask_len);
397+
assert_eq!(dest_len, yes_len);
398+
assert_eq!(dest_len, no_len);
399+
400+
for i in 0..dest_len {
401+
let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?;
402+
let yes = this.read_immediate(&this.mplace_index(&yes, i)?.into())?;
403+
let no = this.read_immediate(&this.mplace_index(&no, i)?.into())?;
404+
let dest = this.mplace_index(&dest, i)?;
405+
406+
let mask = simd_element_to_bool(mask)?;
407+
let val = if mask { yes } else { no };
408+
this.write_immediate(*val, &dest.into())?;
409+
}
410+
}
399411

400412
// Atomic operations
401413
"atomic_load" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?,

tests/run-pass/portable-simd.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ fn simd_ops_i32() {
2020
assert_eq!(a * b, i32x4::from_array([10, 20, 30, 40]));
2121
assert_eq!(a / b, i32x4::from_array([10, 5, 3, 2]));
2222
assert_eq!(a / i32x4::splat(2), i32x4::splat(5));
23+
assert_eq!(i32x2::splat(i32::MIN) / i32x2::splat(-1), i32x2::splat(i32::MIN));
2324
assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2]));
25+
assert_eq!(i32x2::splat(i32::MIN) % i32x2::splat(-1), i32x2::splat(0));
2426
assert_eq!(b << i32x4::splat(2), i32x4::from_array([4, 8, 12, 16]));
2527
assert_eq!(b >> i32x4::splat(1), i32x4::from_array([0, 1, 1, 2]));
2628
assert_eq!(b & i32x4::splat(2), i32x4::from_array([0, 2, 2, 0]));
@@ -29,19 +31,22 @@ fn simd_ops_i32() {
2931

3032
fn simd_intrinsics() {
3133
extern "platform-intrinsic" {
32-
pub(crate) fn simd_eq<T, U>(x: T, y: T) -> U;
33-
pub(crate) fn simd_reduce_any<T>(x: T) -> bool;
34+
fn simd_eq<T, U>(x: T, y: T) -> U;
35+
fn simd_reduce_any<T>(x: T) -> bool;
36+
fn simd_select<M, T>(m: M, yes: T, no: T) -> T;
3437
}
35-
36-
// Make sure simd_eq returns all-1 for `true`
37-
let a = i32x4::splat(10);
38-
let b = i32x4::from_array([1, 2, 10, 4]);
39-
let c: i32x4 = unsafe { simd_eq(a, b) };
40-
assert_eq!(c, i32x4::from_array([0, 0, -1, 0]));
41-
4238
unsafe {
39+
// Make sure simd_eq returns all-1 for `true`
40+
let a = i32x4::splat(10);
41+
let b = i32x4::from_array([1, 2, 10, 4]);
42+
let c: i32x4 = simd_eq(a, b);
43+
assert_eq!(c, i32x4::from_array([0, 0, -1, 0]));
44+
4345
assert!(!simd_reduce_any(i32x4::splat(0)));
4446
assert!(simd_reduce_any(i32x4::splat(-1)));
47+
48+
assert_eq!(simd_select(i8x4::from_array([0, -1, -1, 0]), a, b), i32x4::from_array([1, 10, 10, 4]));
49+
assert_eq!(simd_select(i8x4::from_array([0, -1, -1, 0]), b, a), i32x4::from_array([10, 2, 10, 10]));
4550
}
4651
}
4752

0 commit comments

Comments
 (0)