Skip to content

Commit 53c5840

Browse files
authored
Rollup merge of rust-lang#129403 - scottmcm:only-array-simd, r=compiler-errors
Ban non-array SIMD Nearing the end of rust-lang/compiler-team#621 ! Currently blocked on ~~rust-lang/compiler-builtins#673 ~~rust-lang/compiler-builtins#674 ~~rust-lang#129400 ~~rust-lang#129481 for windows.
2 parents 0e172db + b0ac14d commit 53c5840

File tree

122 files changed

+864
-1151
lines changed

Some content is hidden

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

122 files changed

+864
-1151
lines changed

Diff for: compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@
99

1010
#[repr(simd)]
1111
#[derive(Copy, Clone, PartialEq, Debug)]
12-
struct f32x4(pub f32, pub f32, pub f32, pub f32);
12+
struct f32x4(pub [f32; 4]);
1313

1414
use std::intrinsics::simd::*;
1515

1616
fn main() {
17-
let x = f32x4(1.0, 2.0, 3.0, 4.0);
18-
let y = f32x4(2.0, 1.0, 4.0, 3.0);
17+
let x = f32x4([1.0, 2.0, 3.0, 4.0]);
18+
let y = f32x4([2.0, 1.0, 4.0, 3.0]);
1919

2020
#[cfg(not(any(target_arch = "mips", target_arch = "mips64")))]
2121
let nan = f32::NAN;
@@ -24,13 +24,13 @@ fn main() {
2424
#[cfg(any(target_arch = "mips", target_arch = "mips64"))]
2525
let nan = f32::from_bits(f32::NAN.to_bits() - 1);
2626

27-
let n = f32x4(nan, nan, nan, nan);
27+
let n = f32x4([nan, nan, nan, nan]);
2828

2929
unsafe {
3030
let min0 = simd_fmin(x, y);
3131
let min1 = simd_fmin(y, x);
3232
assert_eq!(min0, min1);
33-
let e = f32x4(1.0, 1.0, 3.0, 3.0);
33+
let e = f32x4([1.0, 1.0, 3.0, 3.0]);
3434
assert_eq!(min0, e);
3535
let minn = simd_fmin(x, n);
3636
assert_eq!(minn, x);
@@ -40,7 +40,7 @@ fn main() {
4040
let max0 = simd_fmax(x, y);
4141
let max1 = simd_fmax(y, x);
4242
assert_eq!(max0, max1);
43-
let e = f32x4(2.0, 2.0, 4.0, 4.0);
43+
let e = f32x4([2.0, 2.0, 4.0, 4.0]);
4444
assert_eq!(max0, e);
4545
let maxn = simd_fmax(x, n);
4646
assert_eq!(maxn, x);

Diff for: compiler/rustc_codegen_cranelift/example/std_example.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ fn main() {
166166
enum Never {}
167167
}
168168

169-
foo(I64X2(0, 0));
169+
foo(I64X2([0, 0]));
170170

171171
transmute_fat_pointer();
172172

@@ -204,7 +204,7 @@ fn rust_call_abi() {
204204
}
205205

206206
#[repr(simd)]
207-
struct I64X2(i64, i64);
207+
struct I64X2([i64; 2]);
208208

209209
#[allow(improper_ctypes_definitions)]
210210
extern "C" fn foo(_a: I64X2) {}

Diff for: 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
```

Diff for: compiler/rustc_error_codes/src/error_codes/E0075.md

+12-6
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
```

Diff for: compiler/rustc_error_codes/src/error_codes/E0076.md

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

Diff for: 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
```

Diff for: 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
```

Diff for: 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(),

Diff for: 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]

Diff for: 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 {

Diff for: src/tools/miri/tests/fail/intrinsics/simd-div-by-zero.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ use std::intrinsics::simd::simd_div;
44

55
#[repr(simd)]
66
#[allow(non_camel_case_types)]
7-
struct i32x2(i32, i32);
7+
struct i32x2([i32; 2]);
88

99
fn main() {
1010
unsafe {
11-
let x = i32x2(1, 1);
12-
let y = i32x2(1, 0);
11+
let x = i32x2([1, 1]);
12+
let y = i32x2([1, 0]);
1313
simd_div(x, y); //~ERROR: Undefined Behavior: dividing by zero
1414
}
1515
}

Diff for: src/tools/miri/tests/fail/intrinsics/simd-div-overflow.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ use std::intrinsics::simd::simd_div;
44

55
#[repr(simd)]
66
#[allow(non_camel_case_types)]
7-
struct i32x2(i32, i32);
7+
struct i32x2([i32; 2]);
88

99
fn main() {
1010
unsafe {
11-
let x = i32x2(1, i32::MIN);
12-
let y = i32x2(1, -1);
11+
let x = i32x2([1, i32::MIN]);
12+
let y = i32x2([1, -1]);
1313
simd_div(x, y); //~ERROR: Undefined Behavior: overflow in signed division
1414
}
1515
}

Diff for: src/tools/miri/tests/fail/intrinsics/simd-reduce-invalid-bool.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ use std::intrinsics::simd::simd_reduce_any;
44

55
#[repr(simd)]
66
#[allow(non_camel_case_types)]
7-
struct i32x2(i32, i32);
7+
struct i32x2([i32; 2]);
88

99
fn main() {
1010
unsafe {
11-
let x = i32x2(0, 1);
11+
let x = i32x2([0, 1]);
1212
simd_reduce_any(x); //~ERROR: must be all-0-bits or all-1-bits
1313
}
1414
}

Diff for: src/tools/miri/tests/fail/intrinsics/simd-rem-by-zero.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ use std::intrinsics::simd::simd_rem;
44

55
#[repr(simd)]
66
#[allow(non_camel_case_types)]
7-
struct i32x2(i32, i32);
7+
struct i32x2([i32; 2]);
88

99
fn main() {
1010
unsafe {
11-
let x = i32x2(1, 1);
12-
let y = i32x2(1, 0);
11+
let x = i32x2([1, 1]);
12+
let y = i32x2([1, 0]);
1313
simd_rem(x, y); //~ERROR: Undefined Behavior: calculating the remainder with a divisor of zero
1414
}
1515
}

Diff for: src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ use std::intrinsics::simd::simd_select_bitmask;
55
#[repr(simd)]
66
#[allow(non_camel_case_types)]
77
#[derive(Copy, Clone)]
8-
struct i32x2(i32, i32);
8+
struct i32x2([i32; 2]);
99

1010
fn main() {
1111
unsafe {
12-
let x = i32x2(0, 1);
12+
let x = i32x2([0, 1]);
1313
simd_select_bitmask(0b11111111u8, x, x); //~ERROR: bitmask less than 8 bits long must be filled with 0s for the remaining bits
1414
}
1515
}

Diff for: src/tools/miri/tests/fail/intrinsics/simd-select-invalid-bool.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ use std::intrinsics::simd::simd_select;
55
#[repr(simd)]
66
#[allow(non_camel_case_types)]
77
#[derive(Copy, Clone)]
8-
struct i32x2(i32, i32);
8+
struct i32x2([i32; 2]);
99

1010
fn main() {
1111
unsafe {
12-
let x = i32x2(0, 1);
12+
let x = i32x2([0, 1]);
1313
simd_select(x, x, x); //~ERROR: must be all-0-bits or all-1-bits
1414
}
1515
}

Diff for: src/tools/miri/tests/fail/intrinsics/simd-shl-too-far.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ use std::intrinsics::simd::simd_shl;
44

55
#[repr(simd)]
66
#[allow(non_camel_case_types)]
7-
struct i32x2(i32, i32);
7+
struct i32x2([i32; 2]);
88

99
fn main() {
1010
unsafe {
11-
let x = i32x2(1, 1);
12-
let y = i32x2(100, 0);
11+
let x = i32x2([1, 1]);
12+
let y = i32x2([100, 0]);
1313
simd_shl(x, y); //~ERROR: overflowing shift by 100 in `simd_shl` in lane 0
1414
}
1515
}

0 commit comments

Comments
 (0)