1
Fork 0

Rollup merge of #130268 - RalfJung:simd-shuffle-idx-vector, r=compiler-errors

simd_shuffle: require index argument to be a vector

Remove some codegen hacks by forcing the SIMD shuffle `index` argument to be a vector, which means (thanks to https://github.com/rust-lang/rust/pull/128537) that it will automatically be passed as an immediate in LLVM. The only special-casing we still have is for the extra sanity-checks we add that ensure that the indices are all in-bounds. (And the GCC backend needs to do a bunch of work since the Rust intrinsic is modeled after what LLVM expects, which seems to be quite different from what GCC expects.)

Fixes https://github.com/rust-lang/rust/issues/128738, see that issue for more context.
This commit is contained in:
León Orell Valerian Liehr 2024-09-14 18:12:10 +02:00 committed by GitHub
commit a9dcd7f25d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 220 additions and 304 deletions

View file

@ -132,7 +132,7 @@ codegen_ssa_invalid_monomorphization_simd_return = invalid monomorphization of `
codegen_ssa_invalid_monomorphization_simd_second = invalid monomorphization of `{$name}` intrinsic: expected SIMD second type, found non-SIMD `{$ty}`
codegen_ssa_invalid_monomorphization_simd_shuffle = invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be an array of `u32`, got `{$ty}`
codegen_ssa_invalid_monomorphization_simd_shuffle = invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be a SIMD vector of `u32`, got `{$ty}`
codegen_ssa_invalid_monomorphization_simd_third = invalid monomorphization of `{$name}` intrinsic: expected SIMD third type, found non-SIMD `{$ty}`

View file

@ -915,32 +915,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
};
let args: Vec<_> = args
.iter()
.enumerate()
.map(|(i, arg)| {
// The indices passed to simd_shuffle in the
// third argument must be constant. This is
// checked by the type-checker.
if i == 2 && intrinsic.name == sym::simd_shuffle {
// FIXME: the simd_shuffle argument is actually an array,
// not a vector, so we need this special hack to make sure
// it is passed as an immediate. We should pass the
// shuffle indices as a vector instead to avoid this hack.
if let mir::Operand::Constant(constant) = &arg.node {
let (llval, ty) = self.immediate_const_vector(bx, constant);
return OperandRef {
val: Immediate(llval),
layout: bx.layout_of(ty),
};
} else {
span_bug!(span, "shuffle indices must be constant");
}
}
self.codegen_operand(bx, &arg.node)
})
.collect();
let args: Vec<_> =
args.iter().map(|arg| self.codegen_operand(bx, &arg.node)).collect();
if matches!(intrinsic, ty::IntrinsicDef { name: sym::caller_location, .. }) {
let location = self

View file

@ -1,6 +1,6 @@
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::layout::HasTyCtxt;
use rustc_middle::ty::{self, Ty, ValTree};
use rustc_middle::ty::{self, Ty};
use rustc_middle::{bug, mir, span_bug};
use rustc_target::abi::Abi;
@ -66,15 +66,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
constant: &mir::ConstOperand<'tcx>,
) -> (Bx::Value, Ty<'tcx>) {
let ty = self.monomorphize(constant.ty());
let ty_is_simd = ty.is_simd();
// FIXME: ideally we'd assert that this is a SIMD type, but simd_shuffle
// in its current form relies on a regular array being passed as an
// immediate argument. This hack can be removed once that is fixed.
let field_ty = if ty_is_simd {
ty.simd_size_and_type(bx.tcx()).1
} else {
ty.builtin_index().unwrap()
};
assert!(ty.is_simd());
let field_ty = ty.simd_size_and_type(bx.tcx()).1;
let val = self
.eval_unevaluated_mir_constant_to_valtree(constant)
@ -82,19 +75,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
.map(|x| x.ok())
.flatten()
.map(|val| {
// Depending on whether this is a SIMD type with an array field
// or a type with many fields (one for each elements), the valtree
// is either a single branch with N children, or a root node
// with exactly one child which then in turn has many children.
// So we look at the first child to determine whether it is a
// leaf or whether we have to go one more layer down.
let branch_or_leaf = val.unwrap_branch();
let first = branch_or_leaf.get(0).unwrap();
let field_iter = match first {
ValTree::Branch(_) => first.unwrap_branch().iter(),
ValTree::Leaf(_) => branch_or_leaf.iter(),
};
let values: Vec<_> = field_iter
// A SIMD type has a single field, which is an array.
let fields = val.unwrap_branch();
assert_eq!(fields.len(), 1);
let array = fields[0].unwrap_branch();
// Iterate over the array elements to obtain the values in the vector.
let values: Vec<_> = array
.iter()
.map(|field| {
if let Some(prim) = field.try_to_scalar() {
let layout = bx.layout_of(field_ty);
@ -107,7 +94,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
})
.collect();
if ty_is_simd { bx.const_vector(&values) } else { bx.const_struct(&values, false) }
bx.const_vector(&values)
})
.unwrap_or_else(|| {
bx.tcx().dcx().emit_err(errors::ShuffleIndicesEvaluation { span: constant.span });