Skip to content

Commit b18d59a

Browse files
committed
Ban non-array SIMD
1 parent 1f12b9b commit b18d59a

File tree

110 files changed

+824
-1111
lines changed

Some content is hidden

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

110 files changed

+824
-1111
lines changed

compiler/rustc_error_codes/src/error_codes/E0074.md

+2-2
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
```
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
```
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

+2-2
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

+2-2
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

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

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

compiler/rustc_middle/src/ty/sty.rs

+15-23
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

+2-2
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

+17-14
Original file line numberDiff line numberDiff line change
@@ -30,36 +30,39 @@ trait Sized {}
3030
#[lang = "copy"]
3131
trait Copy {}
3232

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

3538
#[repr(simd)]
36-
pub struct i8x8(i8, i8, i8, i8, i8, i8, i8, i8);
39+
pub struct i8x8([i8; 8]);
3740
#[repr(simd)]
38-
pub struct i16x4(i16, i16, i16, i16);
41+
pub struct i16x4([i16; 4]);
3942
#[repr(simd)]
40-
pub struct i32x2(i32, i32);
43+
pub struct i32x2([i32; 2]);
4144
#[repr(simd)]
42-
pub struct i64x1(i64);
45+
pub struct i64x1([i64; 1]);
4346
#[repr(simd)]
44-
pub struct f16x4(f16, f16, f16, f16);
47+
pub struct f16x4([f16; 4]);
4548
#[repr(simd)]
46-
pub struct f32x2(f32, f32);
49+
pub struct f32x2([f32; 2]);
4750
#[repr(simd)]
48-
pub struct f64x1(f64);
51+
pub struct f64x1([f64; 1]);
4952
#[repr(simd)]
50-
pub struct i8x16(i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8);
53+
pub struct i8x16([i8; 16]);
5154
#[repr(simd)]
52-
pub struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16);
55+
pub struct i16x8([i16; 8]);
5356
#[repr(simd)]
54-
pub struct i32x4(i32, i32, i32, i32);
57+
pub struct i32x4([i32; 4]);
5558
#[repr(simd)]
56-
pub struct i64x2(i64, i64);
59+
pub struct i64x2([i64; 2]);
5760
#[repr(simd)]
58-
pub struct f16x8(f16, f16, f16, f16, f16, f16, f16, f16);
61+
pub struct f16x8([f16; 8]);
5962
#[repr(simd)]
60-
pub struct f32x4(f32, f32, f32, f32);
63+
pub struct f32x4([f32; 4]);
6164
#[repr(simd)]
62-
pub struct f64x2(f64, f64);
65+
pub struct f64x2([f64; 2]);
6366

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

tests/assembly/asm/arm-modifiers.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@ trait Sized {}
2727
#[lang = "copy"]
2828
trait Copy {}
2929

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

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

tests/assembly/asm/arm-types.rs

+15-12
Original file line numberDiff line numberDiff line change
@@ -30,32 +30,35 @@ trait Sized {}
3030
#[lang = "copy"]
3131
trait Copy {}
3232

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

3538
#[repr(simd)]
36-
pub struct i8x8(i8, i8, i8, i8, i8, i8, i8, i8);
39+
pub struct i8x8([i8; 8]);
3740
#[repr(simd)]
38-
pub struct i16x4(i16, i16, i16, i16);
41+
pub struct i16x4([i16; 4]);
3942
#[repr(simd)]
40-
pub struct i32x2(i32, i32);
43+
pub struct i32x2([i32; 2]);
4144
#[repr(simd)]
42-
pub struct i64x1(i64);
45+
pub struct i64x1([i64; 1]);
4346
#[repr(simd)]
44-
pub struct f16x4(f16, f16, f16, f16);
47+
pub struct f16x4([f16; 4]);
4548
#[repr(simd)]
46-
pub struct f32x2(f32, f32);
49+
pub struct f32x2([f32; 2]);
4750
#[repr(simd)]
48-
pub struct i8x16(i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8);
51+
pub struct i8x16([i8; 16]);
4952
#[repr(simd)]
50-
pub struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16);
53+
pub struct i16x8([i16; 8]);
5154
#[repr(simd)]
52-
pub struct i32x4(i32, i32, i32, i32);
55+
pub struct i32x4([i32; 4]);
5356
#[repr(simd)]
54-
pub struct i64x2(i64, i64);
57+
pub struct i64x2([i64; 2]);
5558
#[repr(simd)]
56-
pub struct f16x8(f16, f16, f16, f16, f16, f16, f16, f16);
59+
pub struct f16x8([f16; 8]);
5760
#[repr(simd)]
58-
pub struct f32x4(f32, f32, f32, f32);
61+
pub struct f32x4([f32; 4]);
5962

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

0 commit comments

Comments
 (0)