Auto merge of #121225 - RalfJung:simd-extract-insert-const-idx, r=oli-obk,Amanieu
require simd_insert, simd_extract indices to be constants As discussed in https://github.com/rust-lang/rust/issues/77477 (see in particular [here](https://github.com/rust-lang/rust/issues/77477#issuecomment-703149102)). This PR doesn't touch codegen yet -- the first step is to ensure that the indices are always constants; the second step is to then make use of this fact in backends. Blocked on https://github.com/rust-lang/stdarch/pull/1530 propagating to the rustc repo.
This commit is contained in:
commit
52dba5ffe7
8 changed files with 37 additions and 89 deletions
|
@ -163,7 +163,13 @@ borrowck_returned_lifetime_wrong =
|
||||||
borrowck_returned_ref_escaped =
|
borrowck_returned_ref_escaped =
|
||||||
returns a reference to a captured variable which escapes the closure body
|
returns a reference to a captured variable which escapes the closure body
|
||||||
|
|
||||||
borrowck_simd_shuffle_last_const = last argument of `simd_shuffle` is required to be a `const` item
|
borrowck_simd_intrinsic_arg_const =
|
||||||
|
{$arg ->
|
||||||
|
[1] 1st
|
||||||
|
[2] 2nd
|
||||||
|
[3] 3rd
|
||||||
|
*[other] {$arg}th
|
||||||
|
} argument of `{$intrinsic}` is required to be a `const` item
|
||||||
|
|
||||||
borrowck_suggest_create_freash_reborrow =
|
borrowck_suggest_create_freash_reborrow =
|
||||||
consider reborrowing the `Pin` instead of moving it
|
consider reborrowing the `Pin` instead of moving it
|
||||||
|
|
|
@ -454,8 +454,10 @@ pub(crate) enum TypeNoCopy<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(borrowck_simd_shuffle_last_const)]
|
#[diag(borrowck_simd_intrinsic_arg_const)]
|
||||||
pub(crate) struct SimdShuffleLastConst {
|
pub(crate) struct SimdIntrinsicArgConst {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
pub arg: usize,
|
||||||
|
pub intrinsic: String,
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
|
||||||
use rustc_mir_dataflow::move_paths::MoveData;
|
use rustc_mir_dataflow::move_paths::MoveData;
|
||||||
use rustc_mir_dataflow::ResultsCursor;
|
use rustc_mir_dataflow::ResultsCursor;
|
||||||
|
|
||||||
use crate::session_diagnostics::{MoveUnsized, SimdShuffleLastConst};
|
use crate::session_diagnostics::{MoveUnsized, SimdIntrinsicArgConst};
|
||||||
use crate::{
|
use crate::{
|
||||||
borrow_set::BorrowSet,
|
borrow_set::BorrowSet,
|
||||||
constraints::{OutlivesConstraint, OutlivesConstraintSet},
|
constraints::{OutlivesConstraint, OutlivesConstraintSet},
|
||||||
|
@ -1664,9 +1664,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
|
|
||||||
let func_ty = func.ty(body, self.infcx.tcx);
|
let func_ty = func.ty(body, self.infcx.tcx);
|
||||||
if let ty::FnDef(def_id, _) = *func_ty.kind() {
|
if let ty::FnDef(def_id, _) = *func_ty.kind() {
|
||||||
if let Some(sym::simd_shuffle) = self.tcx().intrinsic(def_id) {
|
// Some of the SIMD intrinsics are special: they need a particular argument to be a constant.
|
||||||
if !matches!(args[2], Spanned { node: Operand::Constant(_), .. }) {
|
// (Eventually this should use const-generics, but those are not up for the task yet:
|
||||||
self.tcx().dcx().emit_err(SimdShuffleLastConst { span: term.source_info.span });
|
// https://github.com/rust-lang/rust/issues/85229.)
|
||||||
|
if let Some(name @ (sym::simd_shuffle | sym::simd_insert | sym::simd_extract)) =
|
||||||
|
self.tcx().intrinsic(def_id)
|
||||||
|
{
|
||||||
|
let idx = match name {
|
||||||
|
sym::simd_shuffle => 2,
|
||||||
|
_ => 1,
|
||||||
|
};
|
||||||
|
if !matches!(args[idx], Spanned { node: Operand::Constant(_), .. }) {
|
||||||
|
self.tcx().dcx().emit_err(SimdIntrinsicArgConst {
|
||||||
|
span: term.source_info.span,
|
||||||
|
arg: idx + 1,
|
||||||
|
intrinsic: name.to_string(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -864,8 +864,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
.map(|(i, arg)| {
|
.map(|(i, arg)| {
|
||||||
// The indices passed to simd_shuffle in the
|
// The indices passed to simd_shuffle in the
|
||||||
// third argument must be constant. This is
|
// third argument must be constant. This is
|
||||||
// checked by const-qualification, which also
|
// checked by the type-checker.
|
||||||
// promotes any complex rvalues to constants.
|
|
||||||
if i == 2 && intrinsic == sym::simd_shuffle {
|
if i == 2 && intrinsic == sym::simd_shuffle {
|
||||||
if let mir::Operand::Constant(constant) = &arg.node {
|
if let mir::Operand::Constant(constant) = &arg.node {
|
||||||
let (llval, ty) = self.simd_shuffle_indices(bx, constant);
|
let (llval, ty) = self.simd_shuffle_indices(bx, constant);
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
// compile-flags: -C no-prepopulate-passes
|
|
||||||
|
|
||||||
#![crate_type = "lib"]
|
|
||||||
|
|
||||||
#![feature(repr_simd, platform_intrinsics, min_const_generics)]
|
|
||||||
#![allow(non_camel_case_types)]
|
|
||||||
|
|
||||||
#[repr(simd)]
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct M(pub f32, pub f32, pub f32, pub f32);
|
|
||||||
|
|
||||||
#[repr(simd)]
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct S<const N: usize>([f32; N]);
|
|
||||||
|
|
||||||
extern "platform-intrinsic" {
|
|
||||||
fn simd_extract<T, U>(x: T, idx: u32) -> U;
|
|
||||||
fn simd_insert<T, U>(x: T, idx: u32, b: U) -> T;
|
|
||||||
}
|
|
||||||
|
|
||||||
// CHECK-LABEL: @extract_m
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe fn extract_m(v: M, i: u32) -> f32 {
|
|
||||||
// CHECK: extractelement <4 x float> %{{v|1|2}}, i32 %i
|
|
||||||
simd_extract(v, i)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CHECK-LABEL: @extract_s
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe fn extract_s(v: S<4>, i: u32) -> f32 {
|
|
||||||
// CHECK: extractelement <4 x float> %{{v|1|2}}, i32 %i
|
|
||||||
simd_extract(v, i)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CHECK-LABEL: @insert_m
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe fn insert_m(v: M, i: u32, j: f32) -> M {
|
|
||||||
// CHECK: insertelement <4 x float> %{{v|0|1}}, float %j, i32 %i
|
|
||||||
simd_insert(v, i, j)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CHECK-LABEL: @insert_s
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe fn insert_s(v: S<4>, i: u32, j: f32) -> S<4> {
|
|
||||||
// CHECK: insertelement <4 x float> %{{v|0|1}}, float %j, i32 %i
|
|
||||||
simd_insert(v, i, j)
|
|
||||||
}
|
|
|
@ -33,12 +33,7 @@ extern "platform-intrinsic" {
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let mut t = T::<i32x4>([0; 4]);
|
let mut t = T::<i32x4>([0; 4]);
|
||||||
unsafe {
|
unsafe {
|
||||||
for i in 0_i32..4 {
|
t = simd_insert(t, 3, 3);
|
||||||
t = simd_insert(t, i as u32, i);
|
assert_eq!(3, simd_extract(t, 3));
|
||||||
}
|
|
||||||
for i in 0_i32..4 {
|
|
||||||
assert_eq!(i, simd_extract(t, i as u32));
|
|
||||||
//~^ ERROR: use of moved value: `t`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,18 +23,6 @@ LL | pub struct T<S: Simd>([S::Lane; S::SIZE]);
|
||||||
= help: try adding a `where` bound using this expression: `where [(); S::SIZE]:`
|
= help: try adding a `where` bound using this expression: `where [(); S::SIZE]:`
|
||||||
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error[E0382]: use of moved value: `t`
|
error: aborting due to 3 previous errors
|
||||||
--> $DIR/array-trait.rs:40:40
|
|
||||||
|
|
|
||||||
LL | let mut t = T::<i32x4>([0; 4]);
|
|
||||||
| ----- move occurs because `t` has type `T<i32x4>`, which does not implement the `Copy` trait
|
|
||||||
...
|
|
||||||
LL | for i in 0_i32..4 {
|
|
||||||
| ----------------- inside of this loop
|
|
||||||
LL | assert_eq!(i, simd_extract(t, i as u32));
|
|
||||||
| ^ value moved here, in previous iteration of loop
|
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
For more information about this error, try `rustc --explain E0077`.
|
||||||
|
|
||||||
Some errors have detailed explanations: E0077, E0382.
|
|
||||||
For more information about an error, try `rustc --explain E0077`.
|
|
||||||
|
|
|
@ -22,21 +22,13 @@ pub fn main() {
|
||||||
let mut s = S([0; 4]);
|
let mut s = S([0; 4]);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
for i in 0_i32..4 {
|
s = simd_insert(s, 3, 3);
|
||||||
s = simd_insert(s, i as u32, i);
|
assert_eq!(3, simd_extract(s, 3));
|
||||||
}
|
|
||||||
for i in 0_i32..4 {
|
|
||||||
assert_eq!(i, simd_extract(s, i as u32));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut t = T::<4>([0; 4]);
|
let mut t = T::<4>([0; 4]);
|
||||||
unsafe {
|
unsafe {
|
||||||
for i in 0_i32..4 {
|
t = simd_insert(t, 3, 3);
|
||||||
t = simd_insert(t, i as u32, i);
|
assert_eq!(3, simd_extract(t, 3));
|
||||||
}
|
|
||||||
for i in 0_i32..4 {
|
|
||||||
assert_eq!(i, simd_extract(t, i as u32));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue