Skip to content

Commit 97b0851

Browse files
authored
Rollup merge of rust-lang#143833 - scottmcm:final-mcp-838, r=compiler-errors
Ban projecting into SIMD types [MCP838] Closes rust-lang/compiler-team#838 The actual compiler change here is tiny; there's just a bazillion tests to update. Since I'm sure I've missed some, for now r? ghost
2 parents e70bd5f + fa7734a commit 97b0851

File tree

59 files changed

+852
-1100
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+852
-1100
lines changed

compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@
1111
#[derive(Copy, Clone, PartialEq, Debug)]
1212
struct f32x4(pub [f32; 4]);
1313

14+
impl f32x4 {
15+
fn into_array(self) -> [f32; 4] {
16+
unsafe { std::mem::transmute(self) }
17+
}
18+
}
19+
1420
use std::intrinsics::simd::*;
1521

1622
fn main() {
@@ -29,22 +35,22 @@ fn main() {
2935
unsafe {
3036
let min0 = simd_fmin(x, y);
3137
let min1 = simd_fmin(y, x);
32-
assert_eq!(min0, min1);
38+
assert_eq!(min0.into_array(), min1.into_array());
3339
let e = f32x4([1.0, 1.0, 3.0, 3.0]);
34-
assert_eq!(min0, e);
40+
assert_eq!(min0.into_array(), e.into_array());
3541
let minn = simd_fmin(x, n);
36-
assert_eq!(minn, x);
42+
assert_eq!(minn.into_array(), x.into_array());
3743
let minn = simd_fmin(y, n);
38-
assert_eq!(minn, y);
44+
assert_eq!(minn.into_array(), y.into_array());
3945

4046
let max0 = simd_fmax(x, y);
4147
let max1 = simd_fmax(y, x);
42-
assert_eq!(max0, max1);
48+
assert_eq!(max0.into_array(), max1.into_array());
4349
let e = f32x4([2.0, 2.0, 4.0, 4.0]);
44-
assert_eq!(max0, e);
50+
assert_eq!(max0.into_array(), e.into_array());
4551
let maxn = simd_fmax(x, n);
46-
assert_eq!(maxn, x);
52+
assert_eq!(maxn.into_array(), x.into_array());
4753
let maxn = simd_fmax(y, n);
48-
assert_eq!(maxn, y);
54+
assert_eq!(maxn.into_array(), y.into_array());
4955
}
5056
}

compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,8 @@ fn main() {
348348
struct V([f64; 2]);
349349

350350
let f = V([0.0, 1.0]);
351-
let _a = f.0[0];
351+
let fp = (&raw const f) as *const [f64; 2];
352+
let _a = (unsafe { &*fp })[0];
352353

353354
stack_val_align();
354355
}

compiler/rustc_codegen_ssa/src/mir/operand.rs

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -329,20 +329,11 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
329329
let offset = self.layout.fields.offset(i);
330330

331331
if !bx.is_backend_ref(self.layout) && bx.is_backend_ref(field) {
332-
if let BackendRepr::SimdVector { count, .. } = self.layout.backend_repr
333-
&& let BackendRepr::Memory { sized: true } = field.backend_repr
334-
&& count.is_power_of_two()
335-
{
336-
assert_eq!(field.size, self.layout.size);
337-
// This is being deprecated, but for now stdarch still needs it for
338-
// Newtype vector of array, e.g. #[repr(simd)] struct S([i32; 4]);
339-
let place = PlaceRef::alloca(bx, field);
340-
self.val.store(bx, place.val.with_type(self.layout));
341-
return bx.load_operand(place);
342-
} else {
343-
// Part of https://github.com/rust-lang/compiler-team/issues/838
344-
bug!("Non-ref type {self:?} cannot project to ref field type {field:?}");
345-
}
332+
// Part of https://github.com/rust-lang/compiler-team/issues/838
333+
span_bug!(
334+
fx.mir.span,
335+
"Non-ref type {self:?} cannot project to ref field type {field:?}",
336+
);
346337
}
347338

348339
let val = if field.is_zst() {

compiler/rustc_mir_transform/src/validate.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
719719
);
720720
}
721721

722+
if adt_def.repr().simd() {
723+
self.fail(
724+
location,
725+
format!(
726+
"Projecting into SIMD type {adt_def:?} is banned by MCP#838"
727+
),
728+
);
729+
}
730+
722731
let var = parent_ty.variant_index.unwrap_or(FIRST_VARIANT);
723732
let Some(field) = adt_def.variant(var).fields.get(f) else {
724733
fail_out_of_bounds(self, location);

src/tools/miri/tests/pass/intrinsics/portable-simd.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -349,12 +349,15 @@ fn simd_mask() {
349349
// Non-power-of-2 multi-byte mask.
350350
#[repr(simd, packed)]
351351
#[allow(non_camel_case_types)]
352-
#[derive(Copy, Clone, Debug, PartialEq)]
352+
#[derive(Copy, Clone)]
353353
struct i32x10([i32; 10]);
354354
impl i32x10 {
355355
fn splat(x: i32) -> Self {
356356
Self([x; 10])
357357
}
358+
fn into_array(self) -> [i32; 10] {
359+
unsafe { std::mem::transmute(self) }
360+
}
358361
}
359362
unsafe {
360363
let mask = i32x10([!0, !0, 0, !0, 0, 0, !0, 0, !0, 0]);
@@ -377,19 +380,22 @@ fn simd_mask() {
377380
i32x10::splat(!0), // yes
378381
i32x10::splat(0), // no
379382
);
380-
assert_eq!(selected1, mask);
381-
assert_eq!(selected2, mask);
383+
assert_eq!(selected1.into_array(), mask.into_array());
384+
assert_eq!(selected2.into_array(), mask.into_array());
382385
}
383386

384387
// Test for a mask where the next multiple of 8 is not a power of two.
385388
#[repr(simd, packed)]
386389
#[allow(non_camel_case_types)]
387-
#[derive(Copy, Clone, Debug, PartialEq)]
390+
#[derive(Copy, Clone)]
388391
struct i32x20([i32; 20]);
389392
impl i32x20 {
390393
fn splat(x: i32) -> Self {
391394
Self([x; 20])
392395
}
396+
fn into_array(self) -> [i32; 20] {
397+
unsafe { std::mem::transmute(self) }
398+
}
393399
}
394400
unsafe {
395401
let mask = i32x20([!0, !0, 0, !0, 0, 0, !0, 0, !0, 0, 0, 0, 0, !0, !0, !0, !0, !0, !0, !0]);
@@ -419,8 +425,8 @@ fn simd_mask() {
419425
i32x20::splat(!0), // yes
420426
i32x20::splat(0), // no
421427
);
422-
assert_eq!(selected1, mask);
423-
assert_eq!(selected2, mask);
428+
assert_eq!(selected1.into_array(), mask.into_array());
429+
assert_eq!(selected2.into_array(), mask.into_array());
424430
}
425431
}
426432

@@ -708,12 +714,12 @@ fn simd_ops_non_pow2() {
708714
let x = SimdPacked([1u32; 3]);
709715
let y = SimdPacked([2u32; 3]);
710716
let z = unsafe { intrinsics::simd_add(x, y) };
711-
assert_eq!({ z.0 }, [3u32; 3]);
717+
assert_eq!(unsafe { *(&raw const z).cast::<[u32; 3]>() }, [3u32; 3]);
712718

713719
let x = SimdPadded([1u32; 3]);
714720
let y = SimdPadded([2u32; 3]);
715721
let z = unsafe { intrinsics::simd_add(x, y) };
716-
assert_eq!(z.0, [3u32; 3]);
722+
assert_eq!(unsafe { *(&raw const z).cast::<[u32; 3]>() }, [3u32; 3]);
717723
}
718724

719725
fn main() {

tests/auxiliary/minisimd.rs

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
//! Auxiliary crate for tests that need SIMD types.
2+
//!
3+
//! Historically the tests just made their own, but projections into simd types
4+
//! was banned by <https://github.com/rust-lang/compiler-team/issues/838>, which
5+
//! breaks `derive(Clone)`, so this exists to give easily-usable types that can
6+
//! be used without copy-pasting the definitions of the helpers everywhere.
7+
//!
8+
//! This makes no attempt to guard against ICEs. Using it with proper types
9+
//! and such is your responsibility in the tests you write.
10+
11+
#![allow(unused)]
12+
#![allow(non_camel_case_types)]
13+
14+
// The field is currently left `pub` for convenience in porting tests, many of
15+
// which attempt to just construct it directly. That still works; it's just the
16+
// `.0` projection that doesn't.
17+
#[repr(simd)]
18+
#[derive(Copy, Eq)]
19+
pub struct Simd<T, const N: usize>(pub [T; N]);
20+
21+
impl<T: Copy, const N: usize> Clone for Simd<T, N> {
22+
fn clone(&self) -> Self {
23+
*self
24+
}
25+
}
26+
27+
impl<T: PartialEq, const N: usize> PartialEq for Simd<T, N> {
28+
fn eq(&self, other: &Self) -> bool {
29+
self.as_array() == other.as_array()
30+
}
31+
}
32+
33+
impl<T: core::fmt::Debug, const N: usize> core::fmt::Debug for Simd<T, N> {
34+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
35+
<[T; N] as core::fmt::Debug>::fmt(self.as_array(), f)
36+
}
37+
}
38+
39+
impl<T, const N: usize> core::ops::Index<usize> for Simd<T, N> {
40+
type Output = T;
41+
fn index(&self, i: usize) -> &T {
42+
&self.as_array()[i]
43+
}
44+
}
45+
46+
impl<T, const N: usize> Simd<T, N> {
47+
pub const fn from_array(a: [T; N]) -> Self {
48+
Simd(a)
49+
}
50+
pub fn as_array(&self) -> &[T; N] {
51+
let p: *const Self = self;
52+
unsafe { &*p.cast::<[T; N]>() }
53+
}
54+
pub fn into_array(self) -> [T; N]
55+
where
56+
T: Copy,
57+
{
58+
*self.as_array()
59+
}
60+
}
61+
62+
pub type u8x2 = Simd<u8, 2>;
63+
pub type u8x4 = Simd<u8, 4>;
64+
pub type u8x8 = Simd<u8, 8>;
65+
pub type u8x16 = Simd<u8, 16>;
66+
pub type u8x32 = Simd<u8, 32>;
67+
pub type u8x64 = Simd<u8, 64>;
68+
69+
pub type u16x2 = Simd<u16, 2>;
70+
pub type u16x4 = Simd<u16, 4>;
71+
pub type u16x8 = Simd<u16, 8>;
72+
pub type u16x16 = Simd<u16, 16>;
73+
pub type u16x32 = Simd<u16, 32>;
74+
75+
pub type u32x2 = Simd<u32, 2>;
76+
pub type u32x4 = Simd<u32, 4>;
77+
pub type u32x8 = Simd<u32, 8>;
78+
pub type u32x16 = Simd<u32, 16>;
79+
80+
pub type u64x2 = Simd<u64, 2>;
81+
pub type u64x4 = Simd<u64, 4>;
82+
pub type u64x8 = Simd<u64, 8>;
83+
84+
pub type u128x2 = Simd<u128, 2>;
85+
pub type u128x4 = Simd<u128, 4>;
86+
87+
pub type i8x2 = Simd<i8, 2>;
88+
pub type i8x4 = Simd<i8, 4>;
89+
pub type i8x8 = Simd<i8, 8>;
90+
pub type i8x16 = Simd<i8, 16>;
91+
pub type i8x32 = Simd<i8, 32>;
92+
pub type i8x64 = Simd<i8, 64>;
93+
94+
pub type i16x2 = Simd<i16, 2>;
95+
pub type i16x4 = Simd<i16, 4>;
96+
pub type i16x8 = Simd<i16, 8>;
97+
pub type i16x16 = Simd<i16, 16>;
98+
pub type i16x32 = Simd<i16, 32>;
99+
100+
pub type i32x2 = Simd<i32, 2>;
101+
pub type i32x4 = Simd<i32, 4>;
102+
pub type i32x8 = Simd<i32, 8>;
103+
pub type i32x16 = Simd<i32, 16>;
104+
105+
pub type i64x2 = Simd<i64, 2>;
106+
pub type i64x4 = Simd<i64, 4>;
107+
pub type i64x8 = Simd<i64, 8>;
108+
109+
pub type i128x2 = Simd<i128, 2>;
110+
pub type i128x4 = Simd<i128, 4>;
111+
112+
pub type f32x2 = Simd<f32, 2>;
113+
pub type f32x4 = Simd<f32, 4>;
114+
pub type f32x8 = Simd<f32, 8>;
115+
pub type f32x16 = Simd<f32, 16>;
116+
117+
pub type f64x2 = Simd<f64, 2>;
118+
pub type f64x4 = Simd<f64, 4>;
119+
pub type f64x8 = Simd<f64, 8>;
120+
121+
// The field is currently left `pub` for convenience in porting tests, many of
122+
// which attempt to just construct it directly. That still works; it's just the
123+
// `.0` projection that doesn't.
124+
#[repr(simd, packed)]
125+
#[derive(Copy)]
126+
pub struct PackedSimd<T, const N: usize>(pub [T; N]);
127+
128+
impl<T: Copy, const N: usize> Clone for PackedSimd<T, N> {
129+
fn clone(&self) -> Self {
130+
*self
131+
}
132+
}
133+
134+
impl<T: PartialEq, const N: usize> PartialEq for PackedSimd<T, N> {
135+
fn eq(&self, other: &Self) -> bool {
136+
self.as_array() == other.as_array()
137+
}
138+
}
139+
140+
impl<T: core::fmt::Debug, const N: usize> core::fmt::Debug for PackedSimd<T, N> {
141+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
142+
<[T; N] as core::fmt::Debug>::fmt(self.as_array(), f)
143+
}
144+
}
145+
146+
impl<T, const N: usize> PackedSimd<T, N> {
147+
pub const fn from_array(a: [T; N]) -> Self {
148+
PackedSimd(a)
149+
}
150+
pub fn as_array(&self) -> &[T; N] {
151+
let p: *const Self = self;
152+
unsafe { &*p.cast::<[T; N]>() }
153+
}
154+
pub fn into_array(self) -> [T; N]
155+
where
156+
T: Copy,
157+
{
158+
*self.as_array()
159+
}
160+
}

tests/codegen/const-vector.rs

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,9 @@
1616
#![feature(mips_target_feature)]
1717
#![allow(non_camel_case_types)]
1818

19-
// Setting up structs that can be used as const vectors
20-
#[repr(simd)]
21-
#[derive(Clone)]
22-
pub struct i8x2([i8; 2]);
23-
24-
#[repr(simd)]
25-
#[derive(Clone)]
26-
pub struct f32x2([f32; 2]);
27-
28-
#[repr(simd, packed)]
29-
#[derive(Copy, Clone)]
30-
pub struct Simd<T, const N: usize>([T; N]);
19+
#[path = "../auxiliary/minisimd.rs"]
20+
mod minisimd;
21+
use minisimd::{PackedSimd as Simd, f32x2, i8x2};
3122

3223
// The following functions are required for the tests to ensure
3324
// that they are called with a const vector
@@ -45,7 +36,7 @@ extern "unadjusted" {
4536

4637
// Ensure the packed variant of the simd struct does not become a const vector
4738
// if the size is not a power of 2
48-
// CHECK: %"Simd<i32, 3>" = type { [3 x i32] }
39+
// CHECK: %"minisimd::PackedSimd<i32, 3>" = type { [3 x i32] }
4940

5041
#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
5142
#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
@@ -54,27 +45,34 @@ extern "unadjusted" {
5445
pub fn do_call() {
5546
unsafe {
5647
// CHECK: call void @test_i8x2(<2 x i8> <i8 32, i8 64>
57-
test_i8x2(const { i8x2([32, 64]) });
48+
test_i8x2(const { i8x2::from_array([32, 64]) });
5849

5950
// CHECK: call void @test_i8x2_two_args(<2 x i8> <i8 32, i8 64>, <2 x i8> <i8 8, i8 16>
60-
test_i8x2_two_args(const { i8x2([32, 64]) }, const { i8x2([8, 16]) });
51+
test_i8x2_two_args(
52+
const { i8x2::from_array([32, 64]) },
53+
const { i8x2::from_array([8, 16]) },
54+
);
6155

6256
// CHECK: call void @test_i8x2_mixed_args(<2 x i8> <i8 32, i8 64>, i32 43, <2 x i8> <i8 8, i8 16>
63-
test_i8x2_mixed_args(const { i8x2([32, 64]) }, 43, const { i8x2([8, 16]) });
57+
test_i8x2_mixed_args(
58+
const { i8x2::from_array([32, 64]) },
59+
43,
60+
const { i8x2::from_array([8, 16]) },
61+
);
6462

6563
// CHECK: call void @test_i8x2_arr(<2 x i8> <i8 32, i8 64>
66-
test_i8x2_arr(const { i8x2([32, 64]) });
64+
test_i8x2_arr(const { i8x2::from_array([32, 64]) });
6765

6866
// CHECK: call void @test_f32x2(<2 x float> <float 0x3FD47AE140000000, float 0x3FE47AE140000000>
69-
test_f32x2(const { f32x2([0.32, 0.64]) });
67+
test_f32x2(const { f32x2::from_array([0.32, 0.64]) });
7068

7169
// CHECK: void @test_f32x2_arr(<2 x float> <float 0x3FD47AE140000000, float 0x3FE47AE140000000>
72-
test_f32x2_arr(const { f32x2([0.32, 0.64]) });
70+
test_f32x2_arr(const { f32x2::from_array([0.32, 0.64]) });
7371

7472
// CHECK: call void @test_simd(<4 x i32> <i32 2, i32 4, i32 6, i32 8>
7573
test_simd(const { Simd::<i32, 4>([2, 4, 6, 8]) });
7674

77-
// CHECK: call void @test_simd_unaligned(%"Simd<i32, 3>" %1
75+
// CHECK: call void @test_simd_unaligned(%"minisimd::PackedSimd<i32, 3>" %1
7876
test_simd_unaligned(const { Simd::<i32, 3>([2, 4, 6]) });
7977
}
8078
}

0 commit comments

Comments
 (0)