Skip to content

Commit d2309c2

Browse files
committed
Ban non-array SIMD
1 parent 712463d commit d2309c2

File tree

111 files changed

+826
-1113
lines changed

Some content is hidden

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

111 files changed

+826
-1113
lines changed

compiler/rustc_error_codes/src/error_codes/E0074.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ This will cause an error:
1111
#![feature(repr_simd)]
1212
1313
#[repr(simd)]
14-
struct Bad<T>(T, T, T, T);
14+
struct Bad<T>([T; 4]);
1515
```
1616

1717
This will not:
@@ -20,5 +20,5 @@ This will not:
2020
#![feature(repr_simd)]
2121
2222
#[repr(simd)]
23-
struct Good(u32, u32, u32, u32);
23+
struct Good([u32; 4]);
2424
```
Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
A `#[simd]` attribute was applied to an empty tuple struct.
1+
A `#[simd]` attribute was applied to an empty or multi-field struct.
22

3-
Erroneous code example:
3+
Erroneous code examples:
44

55
```compile_fail,E0075
66
#![feature(repr_simd)]
@@ -9,15 +9,21 @@ Erroneous code example:
99
struct Bad; // error!
1010
```
1111

12-
The `#[simd]` attribute can only be applied to non empty tuple structs, because
13-
it doesn't make sense to try to use SIMD operations when there are no values to
14-
operate on.
12+
```compile_fail,E0075
13+
#![feature(repr_simd)]
14+
15+
#[repr(simd)]
16+
struct Bad([u32; 1], [u32; 1]); // error!
17+
```
18+
19+
The `#[simd]` attribute can only be applied to a single-field struct, because
20+
the one field must be the array of values in the vector.
1521

1622
Fixed example:
1723

1824
```
1925
#![feature(repr_simd)]
2026
2127
#[repr(simd)]
22-
struct Good(u32); // ok!
28+
struct Good([u32; 2]); // ok!
2329
```
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
All types in a tuple struct aren't the same when using the `#[simd]`
1+
The type of the field in a tuple struct isn't an array when using the `#[simd]`
22
attribute.
33

44
Erroneous code example:
@@ -7,18 +7,18 @@ Erroneous code example:
77
#![feature(repr_simd)]
88
99
#[repr(simd)]
10-
struct Bad(u16, u32, u32 u32); // error!
10+
struct Bad(u16); // error!
1111
```
1212

1313
When using the `#[simd]` attribute to automatically use SIMD operations in tuple
14-
struct, the types in the struct must all be of the same type, or the compiler
15-
will trigger this error.
14+
structs, if you want a single-lane vector then the field must be a 1-element
15+
array, or the compiler will trigger this error.
1616

1717
Fixed example:
1818

1919
```
2020
#![feature(repr_simd)]
2121
2222
#[repr(simd)]
23-
struct Good(u32, u32, u32, u32); // ok!
23+
struct Good([u16; 1]); // ok!
2424
```

compiler/rustc_error_codes/src/error_codes/E0077.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Erroneous code example:
77
#![feature(repr_simd)]
88
99
#[repr(simd)]
10-
struct Bad(String); // error!
10+
struct Bad([String; 2]); // error!
1111
```
1212

1313
When using the `#[simd]` attribute on a tuple struct, the elements in the tuple
@@ -19,5 +19,5 @@ Fixed example:
1919
#![feature(repr_simd)]
2020
2121
#[repr(simd)]
22-
struct Good(u32, u32, u32, u32); // ok!
22+
struct Good([u32; 4]); // ok!
2323
```

compiler/rustc_error_codes/src/error_codes/E0511.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ The generic type has to be a SIMD type. Example:
2323
2424
#[repr(simd)]
2525
#[derive(Copy, Clone)]
26-
struct i32x2(i32, i32);
26+
struct i32x2([i32; 2]);
2727
2828
extern "rust-intrinsic" {
2929
fn simd_add<T>(a: T, b: T) -> T;
3030
}
3131
32-
unsafe { simd_add(i32x2(0, 0), i32x2(1, 2)); } // ok!
32+
unsafe { simd_add(i32x2([0, 0]), i32x2([1, 2])); } // ok!
3333
```

compiler/rustc_hir_analysis/src/check/check.rs

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,20 +1064,29 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
10641064
struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit();
10651065
return;
10661066
}
1067-
let e = fields[FieldIdx::ZERO].ty(tcx, args);
1068-
if !fields.iter().all(|f| f.ty(tcx, args) == e) {
1069-
struct_span_code_err!(tcx.dcx(), sp, E0076, "SIMD vector should be homogeneous")
1070-
.with_span_label(sp, "SIMD elements must have the same type")
1067+
1068+
let array_field = &fields[FieldIdx::ZERO];
1069+
let array_ty = array_field.ty(tcx, args);
1070+
let ty::Array(element_ty, len_const) = array_ty.kind() else {
1071+
struct_span_code_err!(
1072+
tcx.dcx(),
1073+
sp,
1074+
E0076,
1075+
"SIMD vector's only field must be an array"
1076+
)
1077+
.with_span_label(tcx.def_span(array_field.did), "not an array")
1078+
.emit();
1079+
return;
1080+
};
1081+
1082+
if let Some(second_field) = fields.get(FieldIdx::from_u32(1)) {
1083+
struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot have multiple fields")
1084+
.with_span_label(tcx.def_span(second_field.did), "excess field")
10711085
.emit();
10721086
return;
10731087
}
10741088

1075-
let len = if let ty::Array(_ty, c) = e.kind() {
1076-
c.try_eval_target_usize(tcx, tcx.param_env(def.did()))
1077-
} else {
1078-
Some(fields.len() as u64)
1079-
};
1080-
if let Some(len) = len {
1089+
if let Some(len) = len_const.try_eval_target_usize(tcx, tcx.param_env(def.did())) {
10811090
if len == 0 {
10821091
struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit();
10831092
return;
@@ -1097,16 +1106,9 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
10971106
// These are scalar types which directly match a "machine" type
10981107
// Yes: Integers, floats, "thin" pointers
10991108
// No: char, "fat" pointers, compound types
1100-
match e.kind() {
1101-
ty::Param(_) => (), // pass struct<T>(T, T, T, T) through, let monomorphization catch errors
1102-
ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_, _) => (), // struct(u8, u8, u8, u8) is ok
1103-
ty::Array(t, _) if matches!(t.kind(), ty::Param(_)) => (), // pass struct<T>([T; N]) through, let monomorphization catch errors
1104-
ty::Array(t, _clen)
1105-
if matches!(
1106-
t.kind(),
1107-
ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_, _)
1108-
) =>
1109-
{ /* struct([f32; 4]) is ok */ }
1109+
match element_ty.kind() {
1110+
ty::Param(_) => (), // pass struct<T>([T; 4]) through, let monomorphization catch errors
1111+
ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_, _) => (), // struct([u8; 4]) is ok
11101112
_ => {
11111113
struct_span_code_err!(
11121114
tcx.dcx(),

compiler/rustc_middle/src/ty/sty.rs

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,29 +1091,21 @@ impl<'tcx> Ty<'tcx> {
10911091
}
10921092

10931093
pub fn simd_size_and_type(self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
1094-
match self.kind() {
1095-
Adt(def, args) => {
1096-
assert!(def.repr().simd(), "`simd_size_and_type` called on non-SIMD type");
1097-
let variant = def.non_enum_variant();
1098-
let f0_ty = variant.fields[FieldIdx::ZERO].ty(tcx, args);
1099-
1100-
match f0_ty.kind() {
1101-
// If the first field is an array, we assume it is the only field and its
1102-
// elements are the SIMD components.
1103-
Array(f0_elem_ty, f0_len) => {
1104-
// FIXME(repr_simd): https://github.com/rust-lang/rust/pull/78863#discussion_r522784112
1105-
// The way we evaluate the `N` in `[T; N]` here only works since we use
1106-
// `simd_size_and_type` post-monomorphization. It will probably start to ICE
1107-
// if we use it in generic code. See the `simd-array-trait` ui test.
1108-
(f0_len.eval_target_usize(tcx, ParamEnv::empty()), *f0_elem_ty)
1109-
}
1110-
// Otherwise, the fields of this Adt are the SIMD components (and we assume they
1111-
// all have the same type).
1112-
_ => (variant.fields.len() as u64, f0_ty),
1113-
}
1114-
}
1115-
_ => bug!("`simd_size_and_type` called on invalid type"),
1116-
}
1094+
let Adt(def, args) = self.kind() else {
1095+
bug!("`simd_size_and_type` called on invalid type")
1096+
};
1097+
assert!(def.repr().simd(), "`simd_size_and_type` called on non-SIMD type");
1098+
let variant = def.non_enum_variant();
1099+
assert_eq!(variant.fields.len(), 1);
1100+
let field_ty = variant.fields[FieldIdx::ZERO].ty(tcx, args);
1101+
let Array(f0_elem_ty, f0_len) = field_ty.kind() else {
1102+
bug!("Simd type has non-array field type {field_ty:?}")
1103+
};
1104+
// FIXME(repr_simd): https://github.com/rust-lang/rust/pull/78863#discussion_r522784112
1105+
// The way we evaluate the `N` in `[T; N]` here only works since we use
1106+
// `simd_size_and_type` post-monomorphization. It will probably start to ICE
1107+
// if we use it in generic code. See the `simd-array-trait` ui test.
1108+
(f0_len.eval_target_usize(tcx, ParamEnv::empty()), *f0_elem_ty)
11171109
}
11181110

11191111
#[inline]

library/alloc/benches/slice.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,10 +336,10 @@ reverse!(reverse_u32, u32, |x| x as u32);
336336
reverse!(reverse_u64, u64, |x| x as u64);
337337
reverse!(reverse_u128, u128, |x| x as u128);
338338
#[repr(simd)]
339-
struct F64x4(f64, f64, f64, f64);
339+
struct F64x4([f64; 4]);
340340
reverse!(reverse_simd_f64x4, F64x4, |x| {
341341
let x = x as f64;
342-
F64x4(x, x, x, x)
342+
F64x4([x, x, x, x])
343343
});
344344

345345
macro_rules! rotate {

tests/assembly/asm/aarch64-types.rs

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,36 +31,39 @@ trait Sized {}
3131
#[lang = "copy"]
3232
trait Copy {}
3333

34+
// Do we really need to use no_core for this?!?
35+
impl<T: Copy, const N: usize> Copy for [T; N] {}
36+
3437
type ptr = *mut u8;
3538

3639
#[repr(simd)]
37-
pub struct i8x8(i8, i8, i8, i8, i8, i8, i8, i8);
40+
pub struct i8x8([i8; 8]);
3841
#[repr(simd)]
39-
pub struct i16x4(i16, i16, i16, i16);
42+
pub struct i16x4([i16; 4]);
4043
#[repr(simd)]
41-
pub struct i32x2(i32, i32);
44+
pub struct i32x2([i32; 2]);
4245
#[repr(simd)]
43-
pub struct i64x1(i64);
46+
pub struct i64x1([i64; 1]);
4447
#[repr(simd)]
45-
pub struct f16x4(f16, f16, f16, f16);
48+
pub struct f16x4([f16; 4]);
4649
#[repr(simd)]
47-
pub struct f32x2(f32, f32);
50+
pub struct f32x2([f32; 2]);
4851
#[repr(simd)]
49-
pub struct f64x1(f64);
52+
pub struct f64x1([f64; 1]);
5053
#[repr(simd)]
51-
pub struct i8x16(i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8);
54+
pub struct i8x16([i8; 16]);
5255
#[repr(simd)]
53-
pub struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16);
56+
pub struct i16x8([i16; 8]);
5457
#[repr(simd)]
55-
pub struct i32x4(i32, i32, i32, i32);
58+
pub struct i32x4([i32; 4]);
5659
#[repr(simd)]
57-
pub struct i64x2(i64, i64);
60+
pub struct i64x2([i64; 2]);
5861
#[repr(simd)]
59-
pub struct f16x8(f16, f16, f16, f16, f16, f16, f16, f16);
62+
pub struct f16x8([f16; 8]);
6063
#[repr(simd)]
61-
pub struct f32x4(f32, f32, f32, f32);
64+
pub struct f32x4([f32; 4]);
6265
#[repr(simd)]
63-
pub struct f64x2(f64, f64);
66+
pub struct f64x2([f64; 2]);
6467

6568
impl Copy for i8 {}
6669
impl Copy for i16 {}

tests/assembly/asm/arm-modifiers.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,11 @@ trait Sized {}
2828
#[lang = "copy"]
2929
trait Copy {}
3030

31+
// Do we really need to use no_core for this?!?
32+
impl<T: Copy, const N: usize> Copy for [T; N] {}
33+
3134
#[repr(simd)]
32-
pub struct f32x4(f32, f32, f32, f32);
35+
pub struct f32x4([f32; 4]);
3336

3437
impl Copy for i32 {}
3538
impl Copy for f32 {}

tests/assembly/asm/arm-types.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,32 +31,35 @@ trait Sized {}
3131
#[lang = "copy"]
3232
trait Copy {}
3333

34+
// Do we really need to use no_core for this?!?
35+
impl<T: Copy, const N: usize> Copy for [T; N] {}
36+
3437
type ptr = *mut u8;
3538

3639
#[repr(simd)]
37-
pub struct i8x8(i8, i8, i8, i8, i8, i8, i8, i8);
40+
pub struct i8x8([i8; 8]);
3841
#[repr(simd)]
39-
pub struct i16x4(i16, i16, i16, i16);
42+
pub struct i16x4([i16; 4]);
4043
#[repr(simd)]
41-
pub struct i32x2(i32, i32);
44+
pub struct i32x2([i32; 2]);
4245
#[repr(simd)]
43-
pub struct i64x1(i64);
46+
pub struct i64x1([i64; 1]);
4447
#[repr(simd)]
45-
pub struct f16x4(f16, f16, f16, f16);
48+
pub struct f16x4([f16; 4]);
4649
#[repr(simd)]
47-
pub struct f32x2(f32, f32);
50+
pub struct f32x2([f32; 2]);
4851
#[repr(simd)]
49-
pub struct i8x16(i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8);
52+
pub struct i8x16([i8; 16]);
5053
#[repr(simd)]
51-
pub struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16);
54+
pub struct i16x8([i16; 8]);
5255
#[repr(simd)]
53-
pub struct i32x4(i32, i32, i32, i32);
56+
pub struct i32x4([i32; 4]);
5457
#[repr(simd)]
55-
pub struct i64x2(i64, i64);
58+
pub struct i64x2([i64; 2]);
5659
#[repr(simd)]
57-
pub struct f16x8(f16, f16, f16, f16, f16, f16, f16, f16);
60+
pub struct f16x8([f16; 8]);
5861
#[repr(simd)]
59-
pub struct f32x4(f32, f32, f32, f32);
62+
pub struct f32x4([f32; 4]);
6063

6164
impl Copy for i8 {}
6265
impl Copy for i16 {}

0 commit comments

Comments
 (0)