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:
commit
a9dcd7f25d
24 changed files with 220 additions and 304 deletions
|
@ -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}`
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 });
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue