Skip to content

Commit 4bf5808

Browse files
authored
Rollup merge of #107973 - saethlin:fix-simd-test-ub, r=workingjubilee
Fix unintentional UB in SIMD tests r? `@workingjubilee`
2 parents 55f36ed + 9c4696b commit 4bf5808

File tree

3 files changed

+60
-121
lines changed

3 files changed

+60
-121
lines changed
+42-104
Original file line numberDiff line numberDiff line change
@@ -1,121 +1,59 @@
11
// run-pass
2-
#![allow(unused_must_use)]
32
// ignore-emscripten FIXME(#45351) hits an LLVM assert
43

5-
#![feature(repr_simd, platform_intrinsics, concat_idents, test)]
6-
#![allow(non_camel_case_types)]
7-
8-
extern crate test;
9-
10-
#[repr(simd)]
11-
#[derive(PartialEq, Debug)]
12-
struct i32x4(i32, i32, i32, i32);
13-
#[repr(simd)]
14-
#[derive(PartialEq, Debug)]
15-
struct i8x4(i8, i8, i8, i8);
16-
17-
#[repr(simd)]
18-
#[derive(PartialEq, Debug)]
19-
struct u32x4(u32, u32, u32, u32);
20-
#[repr(simd)]
21-
#[derive(PartialEq, Debug)]
22-
struct u8x4(u8, u8, u8, u8);
23-
24-
#[repr(simd)]
25-
#[derive(PartialEq, Debug)]
26-
struct f32x4(f32, f32, f32, f32);
27-
28-
#[repr(simd)]
29-
#[derive(PartialEq, Debug)]
30-
struct f64x4(f64, f64, f64, f64);
31-
4+
#![feature(repr_simd, platform_intrinsics)]
325

336
extern "platform-intrinsic" {
347
fn simd_cast<T, U>(x: T) -> U;
358
}
369

37-
const A: i32 = -1234567;
38-
const B: i32 = 12345678;
39-
const C: i32 = -123456789;
40-
const D: i32 = 1234567890;
10+
use std::cmp::{max, min};
4111

42-
trait Foo {
43-
fn is_float() -> bool { false }
44-
fn in_range(x: i32) -> bool;
45-
}
46-
impl Foo for i32 {
47-
fn in_range(_: i32) -> bool { true }
48-
}
49-
impl Foo for i8 {
50-
fn in_range(x: i32) -> bool { -128 <= x && x < 128 }
51-
}
52-
impl Foo for u32 {
53-
fn in_range(x: i32) -> bool { 0 <= x }
54-
}
55-
impl Foo for u8 {
56-
fn in_range(x: i32) -> bool { 0 <= x && x < 128 }
57-
}
58-
impl Foo for f32 {
59-
fn is_float() -> bool { true }
60-
fn in_range(_: i32) -> bool { true }
61-
}
62-
impl Foo for f64 {
63-
fn is_float() -> bool { true }
64-
fn in_range(_: i32) -> bool { true }
65-
}
12+
#[derive(Copy, Clone)]
13+
#[repr(simd)]
14+
struct V<T>([T; 2]);
6615

6716
fn main() {
68-
macro_rules! test {
69-
($from: ident, $to: ident) => {{
70-
// force the casts to actually happen, or else LLVM/rustc
71-
// may fold them and get slightly different results.
72-
let (a, b, c, d) = test::black_box((A as $from, B as $from, C as $from, D as $from));
73-
// the SIMD vectors are all FOOx4, so we can concat_idents
74-
// so we don't have to pass in the extra args to the macro
75-
let mut from = simd_cast(concat_idents!($from, x4)(a, b, c, d));
76-
let mut to = concat_idents!($to, x4)(a as $to,
77-
b as $to,
78-
c as $to,
79-
d as $to);
80-
// assist type inference, it needs to know what `from` is
81-
// for the `if` statements.
82-
to == from;
17+
unsafe {
18+
let u = V::<u32>([i16::MIN as u32, i16::MAX as u32]);
19+
let i: V<i16> = simd_cast(u);
20+
assert_eq!(i.0[0], u.0[0] as i16);
21+
assert_eq!(i.0[1], u.0[1] as i16);
22+
}
8323

84-
// there are platform differences for some out of range
85-
// casts, so we just normalize such things: it's OK for
86-
// "invalid" calculations to result in nonsense answers.
87-
// (e.g., negative float to unsigned integer goes through a
88-
// library routine on the default i686 platforms, and the
89-
// implementation of that routine differs on e.g., Linux
90-
// vs. macOS, resulting in different answers.)
91-
if $from::is_float() {
92-
if !$to::in_range(A) { from.0 = 0 as $to; to.0 = 0 as $to; }
93-
if !$to::in_range(B) { from.1 = 0 as $to; to.1 = 0 as $to; }
94-
if !$to::in_range(C) { from.2 = 0 as $to; to.2 = 0 as $to; }
95-
if !$to::in_range(D) { from.3 = 0 as $to; to.3 = 0 as $to; }
96-
}
24+
unsafe {
25+
let f = V::<f32>([i16::MIN as f32, i16::MAX as f32]);
26+
let i: V<i16> = simd_cast(f);
27+
assert_eq!(i.0[0], f.0[0] as i16);
28+
assert_eq!(i.0[1], f.0[1] as i16);
29+
}
9730

98-
assert!(to == from,
99-
"{} -> {} ({:?} != {:?})", stringify!($from), stringify!($to),
100-
from, to);
101-
}}
31+
unsafe {
32+
let f = V::<f32>([u8::MIN as f32, u8::MAX as f32]);
33+
let u: V<u8> = simd_cast(f);
34+
assert_eq!(u.0[0], f.0[0] as u8);
35+
assert_eq!(u.0[1], f.0[1] as u8);
10236
}
103-
macro_rules! tests {
104-
(: $($to: ident),*) => { () };
105-
// repeating the list twice is easier than writing a cartesian
106-
// product macro
107-
($from: ident $(, $from_: ident)*: $($to: ident),*) => {
108-
fn $from() { unsafe { $( test!($from, $to); )* } }
109-
tests!($($from_),*: $($to),*)
110-
};
111-
($($types: ident),*) => {{
112-
tests!($($types),* : $($types),*);
113-
$($types();)*
114-
}}
37+
38+
unsafe {
39+
// We would like to do isize::MIN..=isize::MAX, but those values are not representable in
40+
// an f64, so we clamp to the range of an i32 to prevent running into UB.
41+
let f = V::<f64>([
42+
max(isize::MIN, i32::MIN as isize) as f64,
43+
min(isize::MAX, i32::MAX as isize) as f64,
44+
]);
45+
let i: V<isize> = simd_cast(f);
46+
assert_eq!(i.0[0], f.0[0] as isize);
47+
assert_eq!(i.0[1], f.0[1] as isize);
11548
}
11649

117-
// test various combinations, including truncation,
118-
// signed/unsigned extension, and floating point casts.
119-
tests!(i32, i8, u32, u8, f32);
120-
tests!(i32, u32, f32, f64)
50+
unsafe {
51+
let f = V::<f64>([
52+
max(usize::MIN, u32::MIN as usize) as f64,
53+
min(usize::MAX, u32::MAX as usize) as f64,
54+
]);
55+
let u: V<usize> = simd_cast(f);
56+
assert_eq!(u.0[0], f.0[0] as usize);
57+
assert_eq!(u.0[1], f.0[1] as usize);
58+
}
12159
}

tests/ui/simd/intrinsic/generic-gather-pass.rs

+12-12
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ fn main() {
2424

2525
// reading from *const
2626
unsafe {
27-
let pointer = &x[0] as *const f32;
27+
let pointer = x.as_ptr();
2828
let pointers = x4(
29-
pointer.offset(0) as *const f32,
29+
pointer.offset(0),
3030
pointer.offset(2),
3131
pointer.offset(4),
3232
pointer.offset(6)
@@ -39,9 +39,9 @@ fn main() {
3939

4040
// reading from *mut
4141
unsafe {
42-
let pointer = &mut x[0] as *mut f32;
42+
let pointer = x.as_mut_ptr();
4343
let pointers = x4(
44-
pointer.offset(0) as *mut f32,
44+
pointer.offset(0),
4545
pointer.offset(2),
4646
pointer.offset(4),
4747
pointer.offset(6)
@@ -54,9 +54,9 @@ fn main() {
5454

5555
// writing to *mut
5656
unsafe {
57-
let pointer = &mut x[0] as *mut f32;
57+
let pointer = x.as_mut_ptr();
5858
let pointers = x4(
59-
pointer.offset(0) as *mut f32,
59+
pointer.offset(0),
6060
pointer.offset(2),
6161
pointer.offset(4),
6262
pointer.offset(6)
@@ -85,9 +85,9 @@ fn main() {
8585

8686
// reading from *const
8787
unsafe {
88-
let pointer = &y[0] as *const *const f32;
88+
let pointer = y.as_ptr();
8989
let pointers = x4(
90-
pointer.offset(0) as *const *const f32,
90+
pointer.offset(0),
9191
pointer.offset(2),
9292
pointer.offset(4),
9393
pointer.offset(6)
@@ -100,9 +100,9 @@ fn main() {
100100

101101
// reading from *mut
102102
unsafe {
103-
let pointer = &mut y[0] as *mut *const f32;
103+
let pointer = y.as_mut_ptr();
104104
let pointers = x4(
105-
pointer.offset(0) as *mut *const f32,
105+
pointer.offset(0),
106106
pointer.offset(2),
107107
pointer.offset(4),
108108
pointer.offset(6)
@@ -115,9 +115,9 @@ fn main() {
115115

116116
// writing to *mut
117117
unsafe {
118-
let pointer = &mut y[0] as *mut *const f32;
118+
let pointer = y.as_mut_ptr();
119119
let pointers = x4(
120-
pointer.offset(0) as *mut *const f32,
120+
pointer.offset(0),
121121
pointer.offset(2),
122122
pointer.offset(4),
123123
pointer.offset(6)

tests/ui/simd/issue-89193.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@ extern "platform-intrinsic" {
1717
fn main() {
1818
let x: [usize; 4] = [10, 11, 12, 13];
1919
let default = x4(0_usize, 1, 2, 3);
20-
let mask = x4(1_i32, 1, 1, 1);
20+
let all_set = u8::MAX as i8; // aka -1
21+
let mask = x4(all_set, all_set, all_set, all_set);
2122
let expected = x4(10_usize, 11, 12, 13);
2223

2324
unsafe {
24-
let pointer = &x[0] as *const usize;
25+
let pointer = x.as_ptr();
2526
let pointers = x4(
26-
pointer.offset(0) as *const usize,
27+
pointer.offset(0),
2728
pointer.offset(1),
2829
pointer.offset(2),
2930
pointer.offset(3)
@@ -38,9 +39,9 @@ fn main() {
3839
let expected = x4(10_isize, 11, 12, 13);
3940

4041
unsafe {
41-
let pointer = &x[0] as *const isize;
42+
let pointer = x.as_ptr();
4243
let pointers = x4(
43-
pointer.offset(0) as *const isize,
44+
pointer.offset(0),
4445
pointer.offset(1),
4546
pointer.offset(2),
4647
pointer.offset(3)

0 commit comments

Comments
 (0)