Auto merge of #85919 - workingjubilee:simd-ptrs-are-valid, r=petrochenkov
Allow raw pointers in SIMD types Closes #85915 by loosening the strictness in typechecking and adding a test to guarantee it passes. This still might be too strict, as references currently do pass monomorphization, but my understanding is that they are not guaranteed to be "scalar" in the same way.
This commit is contained in:
commit
4e20754629
8 changed files with 134 additions and 8 deletions
|
@ -1890,11 +1890,6 @@ impl<'tcx> TyS<'tcx> {
|
|||
matches!(self.kind(), Int(ty::IntTy::Isize) | Uint(ty::UintTy::Usize))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_machine(&self) -> bool {
|
||||
matches!(self.kind(), Int(..) | Uint(..) | Float(..))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn has_concrete_skeleton(&self) -> bool {
|
||||
!matches!(self.kind(), Param(_) | Infer(_) | Error(_))
|
||||
|
|
|
@ -1214,10 +1214,19 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
|
|||
}
|
||||
}
|
||||
|
||||
// Check that we use types valid for use in the lanes of a SIMD "vector register"
|
||||
// These are scalar types which directly match a "machine" type
|
||||
// Yes: Integers, floats, "thin" pointers
|
||||
// No: char, "fat" pointers, compound types
|
||||
match e.kind() {
|
||||
ty::Param(_) => { /* struct<T>(T, T, T, T) is ok */ }
|
||||
_ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ }
|
||||
ty::Array(ty, _c) if ty.is_machine() => { /* struct([f32; 4]) */ }
|
||||
ty::Param(_) => (), // pass struct<T>(T, T, T, T) through, let monomorphization catch errors
|
||||
ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_) => (), // struct(u8, u8, u8, u8) is ok
|
||||
ty::Array(t, _clen)
|
||||
if matches!(
|
||||
t.kind(),
|
||||
ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_)
|
||||
) =>
|
||||
{ /* struct([f32; 4]) is ok */ }
|
||||
_ => {
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
|
|
67
src/test/ui/simd/issue-85915-simd-ptrs.rs
Normal file
67
src/test/ui/simd/issue-85915-simd-ptrs.rs
Normal file
|
@ -0,0 +1,67 @@
|
|||
// run-pass
|
||||
// ignore-emscripten
|
||||
|
||||
// Short form of the generic gather/scatter tests,
|
||||
// verifying simd([*const T; N]) and simd([*mut T; N]) pass typeck and work.
|
||||
#![feature(repr_simd, platform_intrinsics)]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
struct cptrx4<T>([*const T; 4]);
|
||||
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
struct mptrx4<T>([*mut T; 4]);
|
||||
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
struct f32x4([f32; 4]);
|
||||
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
struct i32x4([i32; 4]);
|
||||
|
||||
extern "platform-intrinsic" {
|
||||
fn simd_gather<T, U, V>(x: T, y: U, z: V) -> T;
|
||||
fn simd_scatter<T, U, V>(x: T, y: U, z: V) -> ();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut x = [0_f32, 1., 2., 3., 4., 5., 6., 7.];
|
||||
|
||||
let default = f32x4([-3_f32, -3., -3., -3.]);
|
||||
let s_strided = f32x4([0_f32, 2., -3., 6.]);
|
||||
let mask = i32x4([-1_i32, -1, 0, -1]);
|
||||
|
||||
// reading from *const
|
||||
unsafe {
|
||||
let pointer = &x as *const f32;
|
||||
let pointers = cptrx4([
|
||||
pointer.offset(0) as *const f32,
|
||||
pointer.offset(2),
|
||||
pointer.offset(4),
|
||||
pointer.offset(6)
|
||||
]);
|
||||
|
||||
let r_strided = simd_gather(default, pointers, mask);
|
||||
|
||||
assert_eq!(r_strided, s_strided);
|
||||
}
|
||||
|
||||
// writing to *mut
|
||||
unsafe {
|
||||
let pointer = &mut x as *mut f32;
|
||||
let pointers = mptrx4([
|
||||
pointer.offset(0) as *mut f32,
|
||||
pointer.offset(2),
|
||||
pointer.offset(4),
|
||||
pointer.offset(6)
|
||||
]);
|
||||
|
||||
let values = f32x4([42_f32, 43_f32, 44_f32, 45_f32]);
|
||||
simd_scatter(values, pointers, mask);
|
||||
|
||||
assert_eq!(x, [42., 1., 43., 3., 4., 5., 45., 7.]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
// run-pass
|
||||
// ignore-emscripten
|
||||
|
||||
#![feature(extern_types)]
|
||||
#![feature(repr_simd)]
|
||||
|
||||
use std::ptr::NonNull;
|
||||
|
||||
extern {
|
||||
type Extern;
|
||||
}
|
||||
|
||||
#[repr(simd)]
|
||||
struct S<T>(T);
|
||||
|
||||
#[inline(never)]
|
||||
fn identity<T>(v: T) -> T {
|
||||
v
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _v: S<[Option<NonNull<Extern>>; 4]> = identity(S([None; 4]));
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
// build-fail
|
||||
|
||||
#![feature(repr_simd)]
|
||||
|
||||
// error-pattern:monomorphising SIMD type `S<[*mut [u8]; 4]>` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]`
|
||||
|
||||
#[repr(simd)]
|
||||
struct S<T>(T);
|
||||
|
||||
fn main() {
|
||||
let _v: Option<S<[*mut [u8]; 4]>> = None;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
error: monomorphising SIMD type `S<[*mut [u8]; 4]>` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
12
src/test/ui/simd/simd-type-wide-ptr.rs
Normal file
12
src/test/ui/simd/simd-type-wide-ptr.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
// build-fail
|
||||
|
||||
#![feature(repr_simd)]
|
||||
|
||||
// error-pattern:monomorphising SIMD type `S` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]`
|
||||
|
||||
#[repr(simd)]
|
||||
struct S([*mut [u8]; 4]);
|
||||
|
||||
fn main() {
|
||||
let _v: Option<S> = None;
|
||||
}
|
4
src/test/ui/simd/simd-type-wide-ptr.stderr
Normal file
4
src/test/ui/simd/simd-type-wide-ptr.stderr
Normal file
|
@ -0,0 +1,4 @@
|
|||
error: monomorphising SIMD type `S` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
Loading…
Add table
Reference in a new issue