Skip to content

Commit 7774f87

Browse files
authored
Unrolled build for rust-lang#128731
Rollup merge of rust-lang#128731 - RalfJung:simd-shuffle-vector, r=workingjubilee simd_shuffle intrinsic: allow argument to be passed as vector See rust-lang#128738 for context. I'd like to get rid of [this hack](https://github.com/rust-lang/rust/blob/6c0b89dfac65be9a5be12f938f23098ebc36c635/compiler/rustc_codegen_ssa/src/mir/block.rs#L922-L935). rust-lang#128537 almost lets us do that since constant SIMD vectors will then be passed as immediate arguments. However, simd_shuffle for some reason actually takes an *array* as argument, not a vector, so the hack is still required to ensure that the array becomes an immediate (which then later stages of codegen convert into a vector, as that's what LLVM needs). This PR prepares simd_shuffle to also support a vector as the `idx` argument. Once this lands, stdarch can hopefully be updated to pass `idx` as a vector, and then support for arrays can be removed, which finally lets us get rid of that hack.
2 parents bf662eb + daedbd4 commit 7774f87

File tree

6 files changed

+90
-31
lines changed

6 files changed

+90
-31
lines changed

compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs

+10
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,14 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
191191
})
192192
.try_into()
193193
.unwrap(),
194+
_ if idx_ty.is_simd()
195+
&& matches!(
196+
idx_ty.simd_size_and_type(fx.tcx).1.kind(),
197+
ty::Uint(ty::UintTy::U32)
198+
) =>
199+
{
200+
idx_ty.simd_size_and_type(fx.tcx).0.try_into().unwrap()
201+
}
194202
_ => {
195203
fx.tcx.dcx().span_err(
196204
span,
@@ -213,6 +221,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
213221

214222
let total_len = lane_count * 2;
215223

224+
// FIXME: this is a terrible abstraction-breaking hack.
225+
// Find a way to reuse `immediate_const_vector` from `codegen_ssa` instead.
216226
let indexes = {
217227
use rustc_middle::mir::interpret::*;
218228
let idx_const = match &idx.node {

compiler/rustc_codegen_gcc/src/builder.rs

+30-14
Original file line numberDiff line numberDiff line change
@@ -1923,15 +1923,11 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
19231923
v2: RValue<'gcc>,
19241924
mask: RValue<'gcc>,
19251925
) -> RValue<'gcc> {
1926-
let struct_type = mask.get_type().is_struct().expect("mask should be of struct type");
1927-
19281926
// TODO(antoyo): use a recursive unqualified() here.
19291927
let vector_type = v1.get_type().unqualified().dyncast_vector().expect("vector type");
19301928
let element_type = vector_type.get_element_type();
19311929
let vec_num_units = vector_type.get_num_units();
19321930

1933-
let mask_num_units = struct_type.get_field_count();
1934-
let mut vector_elements = vec![];
19351931
let mask_element_type = if element_type.is_integral() {
19361932
element_type
19371933
} else {
@@ -1942,19 +1938,39 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
19421938
#[cfg(not(feature = "master"))]
19431939
self.int_type
19441940
};
1945-
for i in 0..mask_num_units {
1946-
let field = struct_type.get_field(i as i32);
1947-
vector_elements.push(self.context.new_cast(
1948-
self.location,
1949-
mask.access_field(self.location, field).to_rvalue(),
1950-
mask_element_type,
1951-
));
1952-
}
1941+
1942+
let mut mask_elements = if let Some(vector_type) = mask.get_type().dyncast_vector() {
1943+
let mask_num_units = vector_type.get_num_units();
1944+
let mut mask_elements = vec![];
1945+
for i in 0..mask_num_units {
1946+
let index = self.context.new_rvalue_from_long(self.cx.type_u32(), i as _);
1947+
mask_elements.push(self.context.new_cast(
1948+
self.location,
1949+
self.extract_element(mask, index).to_rvalue(),
1950+
mask_element_type,
1951+
));
1952+
}
1953+
mask_elements
1954+
} else {
1955+
let struct_type = mask.get_type().is_struct().expect("mask should be of struct type");
1956+
let mask_num_units = struct_type.get_field_count();
1957+
let mut mask_elements = vec![];
1958+
for i in 0..mask_num_units {
1959+
let field = struct_type.get_field(i as i32);
1960+
mask_elements.push(self.context.new_cast(
1961+
self.location,
1962+
mask.access_field(self.location, field).to_rvalue(),
1963+
mask_element_type,
1964+
));
1965+
}
1966+
mask_elements
1967+
};
1968+
let mask_num_units = mask_elements.len();
19531969

19541970
// NOTE: the mask needs to be the same length as the input vectors, so add the missing
19551971
// elements in the mask if needed.
19561972
for _ in mask_num_units..vec_num_units {
1957-
vector_elements.push(self.context.new_rvalue_zero(mask_element_type));
1973+
mask_elements.push(self.context.new_rvalue_zero(mask_element_type));
19581974
}
19591975

19601976
let result_type = self.context.new_vector_type(element_type, mask_num_units as u64);
@@ -1998,7 +2014,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
19982014

19992015
let new_mask_num_units = std::cmp::max(mask_num_units, vec_num_units);
20002016
let mask_type = self.context.new_vector_type(mask_element_type, new_mask_num_units as u64);
2001-
let mask = self.context.new_rvalue_from_vector(self.location, mask_type, &vector_elements);
2017+
let mask = self.context.new_rvalue_from_vector(self.location, mask_type, &mask_elements);
20022018
let result = self.context.new_rvalue_vector_perm(self.location, v1, v2, mask);
20032019

20042020
if vec_num_units != mask_num_units {

compiler/rustc_codegen_gcc/src/intrinsic/simd.rs

+12-7
Original file line numberDiff line numberDiff line change
@@ -353,19 +353,24 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
353353
}
354354

355355
if name == sym::simd_shuffle {
356-
// Make sure this is actually an array, since typeck only checks the length-suffixed
356+
// Make sure this is actually an array or SIMD vector, since typeck only checks the length-suffixed
357357
// version of this intrinsic.
358-
let n: u64 = match *args[2].layout.ty.kind() {
358+
let idx_ty = args[2].layout.ty;
359+
let n: u64 = match idx_ty.kind() {
359360
ty::Array(ty, len) if matches!(*ty.kind(), ty::Uint(ty::UintTy::U32)) => {
360361
len.try_eval_target_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else(
361362
|| span_bug!(span, "could not evaluate shuffle index array length"),
362363
)
363364
}
364-
_ => return_error!(InvalidMonomorphization::SimdShuffle {
365-
span,
366-
name,
367-
ty: args[2].layout.ty
368-
}),
365+
_ if idx_ty.is_simd()
366+
&& matches!(
367+
idx_ty.simd_size_and_type(bx.cx.tcx).1.kind(),
368+
ty::Uint(ty::UintTy::U32)
369+
) =>
370+
{
371+
idx_ty.simd_size_and_type(bx.cx.tcx).0
372+
}
373+
_ => return_error!(InvalidMonomorphization::SimdShuffle { span, name, ty: idx_ty }),
369374
};
370375
require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
371376

compiler/rustc_codegen_llvm/src/intrinsic.rs

+12-7
Original file line numberDiff line numberDiff line change
@@ -1287,19 +1287,24 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
12871287
}
12881288

12891289
if name == sym::simd_shuffle {
1290-
// Make sure this is actually an array, since typeck only checks the length-suffixed
1290+
// Make sure this is actually an array or SIMD vector, since typeck only checks the length-suffixed
12911291
// version of this intrinsic.
1292-
let n: u64 = match args[2].layout.ty.kind() {
1292+
let idx_ty = args[2].layout.ty;
1293+
let n: u64 = match idx_ty.kind() {
12931294
ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => {
12941295
len.try_eval_target_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else(
12951296
|| span_bug!(span, "could not evaluate shuffle index array length"),
12961297
)
12971298
}
1298-
_ => return_error!(InvalidMonomorphization::SimdShuffle {
1299-
span,
1300-
name,
1301-
ty: args[2].layout.ty
1302-
}),
1299+
_ if idx_ty.is_simd()
1300+
&& matches!(
1301+
idx_ty.simd_size_and_type(bx.cx.tcx).1.kind(),
1302+
ty::Uint(ty::UintTy::U32)
1303+
) =>
1304+
{
1305+
idx_ty.simd_size_and_type(bx.cx.tcx).0
1306+
}
1307+
_ => return_error!(InvalidMonomorphization::SimdShuffle { span, name, ty: idx_ty }),
13031308
};
13041309

13051310
let (out_len, out_ty) = require_simd!(ret_ty, SimdReturn);

library/core/src/intrinsics/simd.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ extern "rust-intrinsic" {
232232
///
233233
/// `T` must be a vector.
234234
///
235-
/// `U` must be a **const** array of `i32`s. This means it must either refer to a named
235+
/// `U` must be a **const** array or vector of `u32`s. This means it must either refer to a named
236236
/// const or be given as an inline const expression (`const { ... }`).
237237
///
238238
/// `V` must be a vector with the same element type as `T` and the same length as `U`.

tests/ui/simd/shuffle.rs

+25-2
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,20 @@
66
#![allow(incomplete_features)]
77
#![feature(adt_const_params)]
88

9+
use std::marker::ConstParamTy;
10+
911
extern "rust-intrinsic" {
1012
fn simd_shuffle<T, I, U>(a: T, b: T, i: I) -> U;
1113
}
1214

13-
#[derive(Copy, Clone)]
15+
#[derive(Copy, Clone, ConstParamTy, PartialEq, Eq)]
1416
#[repr(simd)]
1517
struct Simd<T, const N: usize>([T; N]);
1618

17-
pub unsafe fn __shuffle_vector16<const IDX: [u32; 16], T, U>(x: T, y: T) -> U {
19+
unsafe fn __shuffle_vector16<const IDX: [u32; 16], T, U>(x: T, y: T) -> U {
20+
simd_shuffle(x, y, IDX)
21+
}
22+
unsafe fn __shuffle_vector16_v2<const IDX: Simd<u32, 16>, T, U>(x: T, y: T) -> U {
1823
simd_shuffle(x, y, IDX)
1924
}
2025

@@ -30,6 +35,17 @@ fn main() {
3035
let y: Simd<u8, 2> = simd_shuffle(a, b, I2);
3136
assert_eq!(y.0, [1, 5]);
3237
}
38+
// Test that we can also use a SIMD vector instead of a normal array for the shuffle.
39+
const I1_SIMD: Simd<u32, 4> = Simd([0, 2, 4, 6]);
40+
const I2_SIMD: Simd<u32, 2> = Simd([1, 5]);
41+
unsafe {
42+
let x: Simd<u8, 4> = simd_shuffle(a, b, I1_SIMD);
43+
assert_eq!(x.0, [0, 2, 4, 6]);
44+
45+
let y: Simd<u8, 2> = simd_shuffle(a, b, I2_SIMD);
46+
assert_eq!(y.0, [1, 5]);
47+
}
48+
3349
// Test that an indirection (via an unnamed constant)
3450
// through a const generic parameter also works.
3551
// See https://github.com/rust-lang/rust/issues/113500 for details.
@@ -42,4 +58,11 @@ fn main() {
4258
Simd<u8, 16>,
4359
>(a, b);
4460
}
61+
unsafe {
62+
__shuffle_vector16_v2::<
63+
{ Simd([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]) },
64+
Simd<u8, 16>,
65+
Simd<u8, 16>,
66+
>(a, b);
67+
}
4568
}

0 commit comments

Comments
 (0)