Skip to content

Commit db06d49

Browse files
committed
implement simd_cast, simd_as
1 parent 594a70a commit db06d49

File tree

3 files changed

+161
-26
lines changed

3 files changed

+161
-26
lines changed

src/shims/intrinsics.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,45 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
515515
this.write_immediate(*val, &dest.into())?;
516516
}
517517
}
518+
#[rustfmt::skip]
519+
"simd_cast" | "simd_as" => {
520+
let &[ref op] = check_arg_count(args)?;
521+
let (op, op_len) = this.operand_to_simd(op)?;
522+
let (dest, dest_len) = this.place_to_simd(dest)?;
523+
524+
assert_eq!(dest_len, op_len);
525+
526+
let safe_cast = intrinsic_name == "simd_as";
527+
528+
for i in 0..dest_len {
529+
let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?;
530+
let dest = this.mplace_index(&dest, i)?;
531+
532+
let val = match (op.layout.ty.kind(), dest.layout.ty.kind()) {
533+
// Int-to-(int|float): always safe
534+
(ty::Int(_) | ty::Uint(_), ty::Int(_) | ty::Uint(_) | ty::Float(_)) =>
535+
this.misc_cast(&op, dest.layout.ty)?,
536+
// Float-to-float: always safe
537+
(ty::Float(_), ty::Float(_)) =>
538+
this.misc_cast(&op, dest.layout.ty)?,
539+
// Float-to-int in safe mode
540+
(ty::Float(_), ty::Int(_) | ty::Uint(_)) if safe_cast =>
541+
this.misc_cast(&op, dest.layout.ty)?,
542+
// Float-to-int in unchecked mode
543+
(ty::Float(FloatTy::F32), ty::Int(_) | ty::Uint(_)) if !safe_cast =>
544+
this.float_to_int_unchecked(op.to_scalar()?.to_f32()?, dest.layout.ty)?.into(),
545+
(ty::Float(FloatTy::F64), ty::Int(_) | ty::Uint(_)) if !safe_cast =>
546+
this.float_to_int_unchecked(op.to_scalar()?.to_f64()?, dest.layout.ty)?.into(),
547+
_ =>
548+
throw_unsup_format!(
549+
"Unsupported SIMD cast from element type {} to {}",
550+
op.layout.ty,
551+
dest.layout.ty
552+
),
553+
};
554+
this.write_immediate(val, &dest.into())?;
555+
}
556+
}
518557

519558
// Atomic operations
520559
"atomic_load" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?,
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// error-pattern: cannot be represented in target type `i32`
2+
#![feature(portable_simd)]
3+
use std::simd::*;
4+
5+
fn main() { unsafe {
6+
let _x : i32x2 = f32x2::from_array([f32::MAX, f32::MIN]).to_int_unchecked();
7+
} }

tests/run-pass/portable-simd.rs

Lines changed: 115 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,16 @@ fn simd_ops_f32() {
1313
assert_eq!(a % b, f32x4::from_array([0.0, 0.0, 1.0, 2.0]));
1414
assert_eq!(b.abs(), f32x4::from_array([1.0, 2.0, 3.0, 4.0]));
1515

16-
// FIXME use Mask::from_array once simd_cast is implemented.
17-
assert_eq!(a.lanes_eq(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([0, -1, 0, 0])));
18-
assert_eq!(a.lanes_ne(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([-1, 0, -1, -1])));
19-
assert_eq!(a.lanes_le(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([0, -1, -1, 0])));
20-
assert_eq!(a.lanes_lt(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([0, 0, -1, 0])));
21-
assert_eq!(a.lanes_ge(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([-1, -1, 0, -1])));
22-
assert_eq!(a.lanes_gt(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([-1, 0, 0, -1])));
16+
assert_eq!(a.lanes_eq(f32x4::splat(5.0) * b), Mask::from_array([false, true, false, false]));
17+
assert_eq!(a.lanes_ne(f32x4::splat(5.0) * b), Mask::from_array([true, false, true, true]));
18+
assert_eq!(a.lanes_le(f32x4::splat(5.0) * b), Mask::from_array([false, true, true, false]));
19+
assert_eq!(a.lanes_lt(f32x4::splat(5.0) * b), Mask::from_array([false, false, true, false]));
20+
assert_eq!(a.lanes_ge(f32x4::splat(5.0) * b), Mask::from_array([true, true, false, true]));
21+
assert_eq!(a.lanes_gt(f32x4::splat(5.0) * b), Mask::from_array([true, false, false, true]));
2322

2423
assert_eq!(a.horizontal_sum(), 40.0);
2524
assert_eq!(b.horizontal_sum(), 2.0);
26-
assert_eq!(a.horizontal_product(), 100.0*100.0);
25+
assert_eq!(a.horizontal_product(), 100.0 * 100.0);
2726
assert_eq!(b.horizontal_product(), -24.0);
2827
}
2928

@@ -39,17 +38,16 @@ fn simd_ops_f64() {
3938
assert_eq!(a % b, f64x4::from_array([0.0, 0.0, 1.0, 2.0]));
4039
assert_eq!(b.abs(), f64x4::from_array([1.0, 2.0, 3.0, 4.0]));
4140

42-
// FIXME use Mask::from_array once simd_cast is implemented.
43-
assert_eq!(a.lanes_eq(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([0, -1, 0, 0])));
44-
assert_eq!(a.lanes_ne(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([-1, 0, -1, -1])));
45-
assert_eq!(a.lanes_le(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([0, -1, -1, 0])));
46-
assert_eq!(a.lanes_lt(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([0, 0, -1, 0])));
47-
assert_eq!(a.lanes_ge(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([-1, -1, 0, -1])));
48-
assert_eq!(a.lanes_gt(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([-1, 0, 0, -1])));
41+
assert_eq!(a.lanes_eq(f64x4::splat(5.0) * b), Mask::from_array([false, true, false, false]));
42+
assert_eq!(a.lanes_ne(f64x4::splat(5.0) * b), Mask::from_array([true, false, true, true]));
43+
assert_eq!(a.lanes_le(f64x4::splat(5.0) * b), Mask::from_array([false, true, true, false]));
44+
assert_eq!(a.lanes_lt(f64x4::splat(5.0) * b), Mask::from_array([false, false, true, false]));
45+
assert_eq!(a.lanes_ge(f64x4::splat(5.0) * b), Mask::from_array([true, true, false, true]));
46+
assert_eq!(a.lanes_gt(f64x4::splat(5.0) * b), Mask::from_array([true, false, false, true]));
4947

5048
assert_eq!(a.horizontal_sum(), 40.0);
5149
assert_eq!(b.horizontal_sum(), 2.0);
52-
assert_eq!(a.horizontal_product(), 100.0*100.0);
50+
assert_eq!(a.horizontal_product(), 100.0 * 100.0);
5351
assert_eq!(b.horizontal_product(), -24.0);
5452
}
5553

@@ -71,13 +69,12 @@ fn simd_ops_i32() {
7169
assert_eq!(b | i32x4::splat(2), i32x4::from_array([3, 2, 3, -2]));
7270
assert_eq!(b ^ i32x4::splat(2), i32x4::from_array([3, 0, 1, -2]));
7371

74-
// FIXME use Mask::from_array once simd_cast is implemented.
75-
assert_eq!(a.lanes_eq(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([0, -1, 0, 0])));
76-
assert_eq!(a.lanes_ne(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([-1, 0, -1, -1])));
77-
assert_eq!(a.lanes_le(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([0, -1, -1, 0])));
78-
assert_eq!(a.lanes_lt(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([0, 0, -1, 0])));
79-
assert_eq!(a.lanes_ge(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([-1, -1, 0, -1])));
80-
assert_eq!(a.lanes_gt(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([-1, 0, 0, -1])));
72+
assert_eq!(a.lanes_eq(i32x4::splat(5) * b), Mask::from_array([false, true, false, false]));
73+
assert_eq!(a.lanes_ne(i32x4::splat(5) * b), Mask::from_array([true, false, true, true]));
74+
assert_eq!(a.lanes_le(i32x4::splat(5) * b), Mask::from_array([false, true, true, false]));
75+
assert_eq!(a.lanes_lt(i32x4::splat(5) * b), Mask::from_array([false, false, true, false]));
76+
assert_eq!(a.lanes_ge(i32x4::splat(5) * b), Mask::from_array([true, true, false, true]));
77+
assert_eq!(a.lanes_gt(i32x4::splat(5) * b), Mask::from_array([true, false, false, true]));
8178

8279
assert_eq!(a.horizontal_and(), 10);
8380
assert_eq!(b.horizontal_and(), 0);
@@ -87,10 +84,94 @@ fn simd_ops_i32() {
8784
assert_eq!(b.horizontal_xor(), -4);
8885
assert_eq!(a.horizontal_sum(), 40);
8986
assert_eq!(b.horizontal_sum(), 2);
90-
assert_eq!(a.horizontal_product(), 100*100);
87+
assert_eq!(a.horizontal_product(), 100 * 100);
9188
assert_eq!(b.horizontal_product(), -24);
9289
}
9390

91+
fn simd_mask() {
92+
let intmask = Mask::from_int(i32x4::from_array([0, -1, 0, 0]));
93+
assert_eq!(intmask, Mask::from_array([false, true, false, false]));
94+
assert_eq!(intmask.to_array(), [false, true, false, false]);
95+
}
96+
97+
fn simd_cast() {
98+
// between integer types
99+
assert_eq!(i32x4::from_array([1, 2, 3, -4]), i16x4::from_array([1, 2, 3, -4]).cast());
100+
assert_eq!(i16x4::from_array([1, 2, 3, -4]), i32x4::from_array([1, 2, 3, -4]).cast());
101+
assert_eq!(i32x4::from_array([1, -1, 3, 4]), u64x4::from_array([1, u64::MAX, 3, 4]).cast());
102+
103+
// float -> int
104+
assert_eq!(
105+
i8x4::from_array([127, -128, 127, -128]),
106+
f32x4::from_array([127.99, -128.99, 999.0, -999.0]).cast()
107+
);
108+
assert_eq!(
109+
i32x4::from_array([0, 1, -1, 2147483520]),
110+
f32x4::from_array([
111+
-0.0,
112+
/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd),
113+
/*-0x1.19999ap+0*/ f32::from_bits(0xbf8ccccd),
114+
2147483520.0
115+
])
116+
.cast()
117+
);
118+
assert_eq!(
119+
i32x8::from_array([i32::MAX, i32::MIN, i32::MAX, i32::MIN, i32::MAX, i32::MIN, 0, 0]),
120+
f32x8::from_array([
121+
2147483648.0f32,
122+
-2147483904.0f32,
123+
f32::MAX,
124+
f32::MIN,
125+
f32::INFINITY,
126+
f32::NEG_INFINITY,
127+
f32::NAN,
128+
-f32::NAN,
129+
])
130+
.cast()
131+
);
132+
133+
// int -> float
134+
assert_eq!(
135+
f32x4::from_array([
136+
-2147483648.0,
137+
/*0x1.26580cp+30*/ f32::from_bits(0x4e932c06),
138+
16777220.0,
139+
-16777220.0,
140+
]),
141+
i32x4::from_array([-2147483647i32, 1234567890i32, 16777219i32, -16777219i32]).cast()
142+
);
143+
144+
// float -> float
145+
assert_eq!(
146+
f32x4::from_array([f32::INFINITY, f32::INFINITY, f32::NEG_INFINITY, f32::NEG_INFINITY]),
147+
f64x4::from_array([f64::MAX, f64::INFINITY, f64::MIN, f64::NEG_INFINITY]).cast()
148+
);
149+
150+
// unchecked casts
151+
unsafe {
152+
assert_eq!(
153+
i32x4::from_array([0, 1, -1, 2147483520]),
154+
f32x4::from_array([
155+
-0.0,
156+
/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd),
157+
/*-0x1.19999ap+0*/ f32::from_bits(0xbf8ccccd),
158+
2147483520.0
159+
])
160+
.to_int_unchecked()
161+
);
162+
assert_eq!(
163+
u64x4::from_array([0, 10000000000000000, u64::MAX - 2047, 9223372036854775808]),
164+
f64x4::from_array([
165+
-0.99999999999,
166+
1e16,
167+
(u64::MAX - 1024) as f64,
168+
9223372036854775808.0
169+
])
170+
.to_int_unchecked()
171+
);
172+
}
173+
}
174+
94175
fn simd_intrinsics() {
95176
extern "platform-intrinsic" {
96177
fn simd_eq<T, U>(x: T, y: T) -> U;
@@ -112,14 +193,22 @@ fn simd_intrinsics() {
112193
assert!(simd_reduce_all(i32x4::splat(-1)));
113194
assert!(!simd_reduce_all(i32x2::from_array([0, -1])));
114195

115-
assert_eq!(simd_select(i8x4::from_array([0, -1, -1, 0]), a, b), i32x4::from_array([1, 10, 10, 4]));
116-
assert_eq!(simd_select(i8x4::from_array([0, -1, -1, 0]), b, a), i32x4::from_array([10, 2, 10, 10]));
196+
assert_eq!(
197+
simd_select(i8x4::from_array([0, -1, -1, 0]), a, b),
198+
i32x4::from_array([1, 10, 10, 4])
199+
);
200+
assert_eq!(
201+
simd_select(i8x4::from_array([0, -1, -1, 0]), b, a),
202+
i32x4::from_array([10, 2, 10, 10])
203+
);
117204
}
118205
}
119206

120207
fn main() {
208+
simd_mask();
121209
simd_ops_f32();
122210
simd_ops_f64();
123211
simd_ops_i32();
212+
simd_cast();
124213
simd_intrinsics();
125214
}

0 commit comments

Comments
 (0)