Skip to content

Commit

Permalink
Rollup merge of rust-lang#88855 - calebzulawski:feature/simd_shuffle,…
Browse files Browse the repository at this point in the history
… r=nagisa

Allow simd_shuffle to accept vectors of any length

cc `@rust-lang/project-portable-simd` `@workingjubilee`
  • Loading branch information
JohnTitor committed Sep 19, 2021
2 parents 2f210be + 4a4ca94 commit 5bc783b
Show file tree
Hide file tree
Showing 14 changed files with 171 additions and 35 deletions.
25 changes: 21 additions & 4 deletions compiler/rustc_codegen_llvm/src/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -918,12 +918,29 @@ fn generic_simd_intrinsic(
}

if let Some(stripped) = name_str.strip_prefix("simd_shuffle") {
let n: u64 = stripped.parse().unwrap_or_else(|_| {
span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?")
});
// If this intrinsic is the older "simd_shuffleN" form, simply parse the integer.
// If there is no suffix, use the index array length.
let n: u64 = if stripped.is_empty() {
// Make sure this is actually an array, since typeck only checks the length-suffixed
// version of this intrinsic.
match args[2].layout.ty.kind() {
ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => {
len.try_eval_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else(|| {
span_bug!(span, "could not evaluate shuffle index array length")
})
}
_ => return_error!(
"simd_shuffle index must be an array of `u32`, got `{}`",
args[2].layout.ty
),
}
} else {
stripped.parse().unwrap_or_else(|_| {
span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?")
})
};

require_simd!(ret_ty, "return");

let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
require!(
out_len == n,
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_codegen_ssa/src/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -665,8 +665,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
if i == 2 && intrinsic.as_str().starts_with("simd_shuffle") {
if let mir::Operand::Constant(constant) = arg {
let c = self.eval_mir_constant(constant);
let (llval, ty) =
self.simd_shuffle_indices(&bx, constant.span, constant.ty(), c);
let (llval, ty) = self.simd_shuffle_indices(
&bx,
constant.span,
self.monomorphize(constant.ty()),
c,
);
return OperandRef {
val: Immediate(llval),
layout: bx.layout_of(ty),
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_error_codes/src/error_codes/E0439.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#### Note: this error code is no longer emitted by the compiler.

The length of the platform-intrinsic function `simd_shuffle` wasn't specified.

Erroneous code example:

```compile_fail,E0439
```ignore (no longer emitted)
#![feature(platform_intrinsics)]
extern "platform-intrinsic" {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1212,6 +1212,7 @@ symbols! {
simd_select_bitmask,
simd_shl,
simd_shr,
simd_shuffle,
simd_sub,
simd_trunc,
simd_xor,
Expand Down
7 changes: 5 additions & 2 deletions compiler/rustc_typeck/src/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//! intrinsics that the compiler exposes.

use crate::errors::{
SimdShuffleMissingLength, UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction,
UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction,
WrongNumberOfGenericArgumentsToIntrinsic,
};
use crate::require_same_types;
Expand Down Expand Up @@ -468,14 +468,17 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
| sym::simd_reduce_max
| sym::simd_reduce_min_nanless
| sym::simd_reduce_max_nanless => (2, vec![param(0)], param(1)),
sym::simd_shuffle => (3, vec![param(0), param(0), param(1)], param(2)),
name if name.as_str().starts_with("simd_shuffle") => {
match name.as_str()["simd_shuffle".len()..].parse() {
Ok(n) => {
let params = vec![param(0), param(0), tcx.mk_array(tcx.types.u32, n)];
(2, params, param(1))
}
Err(_) => {
tcx.sess.emit_err(SimdShuffleMissingLength { span: it.span, name });
let msg =
format!("unrecognized platform-specific intrinsic function: `{}`", name);
tcx.sess.struct_span_err(it.span, &msg).emit();
return;
}
}
Expand Down
8 changes: 0 additions & 8 deletions compiler/rustc_typeck/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,6 @@ pub struct AssocTypeBindingNotAllowed {
pub span: Span,
}

#[derive(SessionDiagnostic)]
#[error = "E0439"]
pub struct SimdShuffleMissingLength {
#[message = "invalid `simd_shuffle`, needs length: `{name}`"]
pub span: Span,
pub name: Symbol,
}

#[derive(SessionDiagnostic)]
#[error = "E0436"]
pub struct FunctionalRecordUpdateOnNonStruct {
Expand Down
8 changes: 0 additions & 8 deletions src/test/ui/error-codes/E0439.rs

This file was deleted.

9 changes: 0 additions & 9 deletions src/test/ui/error-codes/E0439.stderr

This file was deleted.

33 changes: 33 additions & 0 deletions src/test/ui/simd-intrinsic/simd-intrinsic-generic-shuffle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// build-fail

// Test that the simd_shuffle intrinsic produces ok-ish error
// messages when misused.

#![feature(repr_simd, platform_intrinsics)]

#[repr(simd)]
#[derive(Copy, Clone)]
pub struct Simd<T, const N: usize>([T; N]);

extern "platform-intrinsic" {
fn simd_shuffle<T, I, U>(a: T, b: T, i: I) -> U;
}

fn main() {
const I: [u32; 2] = [0; 2];
const I2: [f32; 2] = [0.; 2];
let v = Simd::<u32, 4>([0; 4]);

unsafe {
let _: Simd<u32, 2> = simd_shuffle(v, v, I);

let _: Simd<u32, 4> = simd_shuffle(v, v, I);
//~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic

let _: Simd<f32, 2> = simd_shuffle(v, v, I);
//~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic

let _: Simd<u32, 2> = simd_shuffle(v, v, I2);
//~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic
}
}
21 changes: 21 additions & 0 deletions src/test/ui/simd-intrinsic/simd-intrinsic-generic-shuffle.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 2, found `Simd<u32, 4_usize>` with length 4
--> $DIR/simd-intrinsic-generic-shuffle.rs:24:31
|
LL | let _: Simd<u32, 4> = simd_shuffle(v, v, I);
| ^^^^^^^^^^^^^^^^^^^^^

error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `u32` (element of input `Simd<u32, 4_usize>`), found `Simd<f32, 2_usize>` with element type `f32`
--> $DIR/simd-intrinsic-generic-shuffle.rs:27:31
|
LL | let _: Simd<f32, 2> = simd_shuffle(v, v, I);
| ^^^^^^^^^^^^^^^^^^^^^

error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: simd_shuffle index must be an array of `u32`, got `[f32; 2]`
--> $DIR/simd-intrinsic-generic-shuffle.rs:30:31
|
LL | let _: Simd<u32, 2> = simd_shuffle(v, v, I2);
| ^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0511`.
40 changes: 40 additions & 0 deletions src/test/ui/simd/monomorphize-shuffle-index.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//run-pass
#![feature(repr_simd, platform_intrinsics)]

extern "platform-intrinsic" {
fn simd_shuffle<T, I, U>(a: T, b: T, i: I) -> U;
}

#[derive(Copy, Clone)]
#[repr(simd)]
struct Simd<T, const N: usize>([T; N]);

trait Shuffle<const N: usize> {
const I: [u32; N];

unsafe fn shuffle<T, const M: usize>(&self, a: Simd<T, M>, b: Simd<T, M>) -> Simd<T, N> {
simd_shuffle(a, b, Self::I)
}
}

fn main() {
struct I1;
impl Shuffle<4> for I1 {
const I: [u32; 4] = [0, 2, 4, 6];
}

struct I2;
impl Shuffle<2> for I2 {
const I: [u32; 2] = [1, 5];
}

let a = Simd::<u8, 4>([0, 1, 2, 3]);
let b = Simd::<u8, 4>([4, 5, 6, 7]);
unsafe {
let x: Simd<u8, 4> = I1.shuffle(a, b);
assert_eq!(x.0, [0, 2, 4, 6]);

let y: Simd<u8, 2> = I2.shuffle(a, b);
assert_eq!(y.0, [1, 5]);
}
}
10 changes: 10 additions & 0 deletions src/test/ui/simd/shuffle-not-out-of-bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,4 +188,14 @@ fn main() {
48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33,
32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17,
16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));

extern "platform-intrinsic" {
fn simd_shuffle<T, I, U>(a: T, b: T, i: I) -> U;
}
let v = u8x2(0, 0);
const I: [u32; 2] = [4, 4];
unsafe {
let _: u8x2 = simd_shuffle(v, v, I);
//~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic
}
}
8 changes: 7 additions & 1 deletion src/test/ui/simd/shuffle-not-out-of-bounds.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ LL | | 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
|
= note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 6 previous errors
error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 4)
--> $DIR/shuffle-not-out-of-bounds.rs:198:23
|
LL | let _: u8x2 = simd_shuffle(v, v, I);
| ^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 7 previous errors

For more information about this error, try `rustc --explain E0511`.
24 changes: 24 additions & 0 deletions src/test/ui/simd/shuffle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//run-pass
#![feature(repr_simd, platform_intrinsics)]

extern "platform-intrinsic" {
fn simd_shuffle<T, I, U>(a: T, b: T, i: I) -> U;
}

#[derive(Copy, Clone)]
#[repr(simd)]
struct Simd<T, const N: usize>([T; N]);

fn main() {
const I1: [u32; 4] = [0, 2, 4, 6];
const I2: [u32; 2] = [1, 5];
let a = Simd::<u8, 4>([0, 1, 2, 3]);
let b = Simd::<u8, 4>([4, 5, 6, 7]);
unsafe {
let x: Simd<u8, 4> = simd_shuffle(a, b, I1);
assert_eq!(x.0, [0, 2, 4, 6]);

let y: Simd<u8, 2> = simd_shuffle(a, b, I2);
assert_eq!(y.0, [1, 5]);
}
}

0 comments on commit 5bc783b

Please sign in to comment.