mirror of https://github.com/rust-lang/rust.git
Auto merge of #80652 - calebzulawski:simd-lanes, r=nagisa
Improve SIMD type element count validation Resolves rust-lang/stdsimd#53. These changes are motivated by `stdsimd` moving in the direction of const generic vectors, e.g.: ```rust #[repr(simd)] struct SimdF32<const N: usize>([f32; N]); ``` This makes a few changes: * Establishes a maximum SIMD lane count of 2^16 (65536). This value is arbitrary, but attempts to validate lane count before hitting potential errors in the backend. It's not clear what LLVM's maximum lane count is, but cranelift's appears to be much less than `usize::MAX`, at least. * Expands some SIMD intrinsics to support arbitrary lane counts. This resolves the ICE in the linked issue. * Attempts to catch invalid-sized vectors during typeck when possible. Unresolved questions: * Generic-length vectors can't be validated in typeck and are only validated after monomorphization while computing layout. This "works", but the errors simply bail out with no context beyond the name of the type. Should these errors instead return `LayoutError` or otherwise provide context in some way? As it stands, users of `stdsimd` could trivially produce monomorphization errors by making zero-length vectors. cc `@bjorn3`
This commit is contained in:
commit
bb587b1a17
|
@ -380,7 +380,7 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
"rust_eh_personality"
|
||||
};
|
||||
let fty = self.type_variadic_func(&[], self.type_i32());
|
||||
self.declare_cfn(name, fty)
|
||||
self.declare_cfn(name, llvm::UnnamedAddr::Global, fty)
|
||||
}
|
||||
};
|
||||
attributes::apply_target_cpu_attr(self, llfn);
|
||||
|
@ -429,7 +429,7 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
|
||||
fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
|
||||
if self.get_declared_value("main").is_none() {
|
||||
Some(self.declare_cfn("main", fn_type))
|
||||
Some(self.declare_cfn("main", llvm::UnnamedAddr::Global, fn_type))
|
||||
} else {
|
||||
// If the symbol already exists, it is an error: for example, the user wrote
|
||||
// #[no_mangle] extern "C" fn main(..) {..}
|
||||
|
@ -459,8 +459,7 @@ impl CodegenCx<'b, 'tcx> {
|
|||
} else {
|
||||
self.type_variadic_func(&[], ret)
|
||||
};
|
||||
let f = self.declare_cfn(name, fn_ty);
|
||||
llvm::SetUnnamedAddress(f, llvm::UnnamedAddr::No);
|
||||
let f = self.declare_cfn(name, llvm::UnnamedAddr::No, fn_ty);
|
||||
self.intrinsics.borrow_mut().insert(name, f);
|
||||
f
|
||||
}
|
||||
|
@ -498,25 +497,6 @@ impl CodegenCx<'b, 'tcx> {
|
|||
let t_f32 = self.type_f32();
|
||||
let t_f64 = self.type_f64();
|
||||
|
||||
macro_rules! vector_types {
|
||||
($id_out:ident: $elem_ty:ident, $len:expr) => {
|
||||
let $id_out = self.type_vector($elem_ty, $len);
|
||||
};
|
||||
($($id_out:ident: $elem_ty:ident, $len:expr;)*) => {
|
||||
$(vector_types!($id_out: $elem_ty, $len);)*
|
||||
}
|
||||
}
|
||||
vector_types! {
|
||||
t_v2f32: t_f32, 2;
|
||||
t_v4f32: t_f32, 4;
|
||||
t_v8f32: t_f32, 8;
|
||||
t_v16f32: t_f32, 16;
|
||||
|
||||
t_v2f64: t_f64, 2;
|
||||
t_v4f64: t_f64, 4;
|
||||
t_v8f64: t_f64, 8;
|
||||
}
|
||||
|
||||
ifn!("llvm.wasm.trunc.saturate.unsigned.i32.f32", fn(t_f32) -> t_i32);
|
||||
ifn!("llvm.wasm.trunc.saturate.unsigned.i32.f64", fn(t_f64) -> t_i32);
|
||||
ifn!("llvm.wasm.trunc.saturate.unsigned.i64.f32", fn(t_f32) -> t_i64);
|
||||
|
@ -540,124 +520,40 @@ impl CodegenCx<'b, 'tcx> {
|
|||
ifn!("llvm.sideeffect", fn() -> void);
|
||||
|
||||
ifn!("llvm.powi.f32", fn(t_f32, t_i32) -> t_f32);
|
||||
ifn!("llvm.powi.v2f32", fn(t_v2f32, t_i32) -> t_v2f32);
|
||||
ifn!("llvm.powi.v4f32", fn(t_v4f32, t_i32) -> t_v4f32);
|
||||
ifn!("llvm.powi.v8f32", fn(t_v8f32, t_i32) -> t_v8f32);
|
||||
ifn!("llvm.powi.v16f32", fn(t_v16f32, t_i32) -> t_v16f32);
|
||||
ifn!("llvm.powi.f64", fn(t_f64, t_i32) -> t_f64);
|
||||
ifn!("llvm.powi.v2f64", fn(t_v2f64, t_i32) -> t_v2f64);
|
||||
ifn!("llvm.powi.v4f64", fn(t_v4f64, t_i32) -> t_v4f64);
|
||||
ifn!("llvm.powi.v8f64", fn(t_v8f64, t_i32) -> t_v8f64);
|
||||
|
||||
ifn!("llvm.pow.f32", fn(t_f32, t_f32) -> t_f32);
|
||||
ifn!("llvm.pow.v2f32", fn(t_v2f32, t_v2f32) -> t_v2f32);
|
||||
ifn!("llvm.pow.v4f32", fn(t_v4f32, t_v4f32) -> t_v4f32);
|
||||
ifn!("llvm.pow.v8f32", fn(t_v8f32, t_v8f32) -> t_v8f32);
|
||||
ifn!("llvm.pow.v16f32", fn(t_v16f32, t_v16f32) -> t_v16f32);
|
||||
ifn!("llvm.pow.f64", fn(t_f64, t_f64) -> t_f64);
|
||||
ifn!("llvm.pow.v2f64", fn(t_v2f64, t_v2f64) -> t_v2f64);
|
||||
ifn!("llvm.pow.v4f64", fn(t_v4f64, t_v4f64) -> t_v4f64);
|
||||
ifn!("llvm.pow.v8f64", fn(t_v8f64, t_v8f64) -> t_v8f64);
|
||||
|
||||
ifn!("llvm.sqrt.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.sqrt.v2f32", fn(t_v2f32) -> t_v2f32);
|
||||
ifn!("llvm.sqrt.v4f32", fn(t_v4f32) -> t_v4f32);
|
||||
ifn!("llvm.sqrt.v8f32", fn(t_v8f32) -> t_v8f32);
|
||||
ifn!("llvm.sqrt.v16f32", fn(t_v16f32) -> t_v16f32);
|
||||
ifn!("llvm.sqrt.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.sqrt.v2f64", fn(t_v2f64) -> t_v2f64);
|
||||
ifn!("llvm.sqrt.v4f64", fn(t_v4f64) -> t_v4f64);
|
||||
ifn!("llvm.sqrt.v8f64", fn(t_v8f64) -> t_v8f64);
|
||||
|
||||
ifn!("llvm.sin.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.sin.v2f32", fn(t_v2f32) -> t_v2f32);
|
||||
ifn!("llvm.sin.v4f32", fn(t_v4f32) -> t_v4f32);
|
||||
ifn!("llvm.sin.v8f32", fn(t_v8f32) -> t_v8f32);
|
||||
ifn!("llvm.sin.v16f32", fn(t_v16f32) -> t_v16f32);
|
||||
ifn!("llvm.sin.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.sin.v2f64", fn(t_v2f64) -> t_v2f64);
|
||||
ifn!("llvm.sin.v4f64", fn(t_v4f64) -> t_v4f64);
|
||||
ifn!("llvm.sin.v8f64", fn(t_v8f64) -> t_v8f64);
|
||||
|
||||
ifn!("llvm.cos.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.cos.v2f32", fn(t_v2f32) -> t_v2f32);
|
||||
ifn!("llvm.cos.v4f32", fn(t_v4f32) -> t_v4f32);
|
||||
ifn!("llvm.cos.v8f32", fn(t_v8f32) -> t_v8f32);
|
||||
ifn!("llvm.cos.v16f32", fn(t_v16f32) -> t_v16f32);
|
||||
ifn!("llvm.cos.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.cos.v2f64", fn(t_v2f64) -> t_v2f64);
|
||||
ifn!("llvm.cos.v4f64", fn(t_v4f64) -> t_v4f64);
|
||||
ifn!("llvm.cos.v8f64", fn(t_v8f64) -> t_v8f64);
|
||||
|
||||
ifn!("llvm.exp.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.exp.v2f32", fn(t_v2f32) -> t_v2f32);
|
||||
ifn!("llvm.exp.v4f32", fn(t_v4f32) -> t_v4f32);
|
||||
ifn!("llvm.exp.v8f32", fn(t_v8f32) -> t_v8f32);
|
||||
ifn!("llvm.exp.v16f32", fn(t_v16f32) -> t_v16f32);
|
||||
ifn!("llvm.exp.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.exp.v2f64", fn(t_v2f64) -> t_v2f64);
|
||||
ifn!("llvm.exp.v4f64", fn(t_v4f64) -> t_v4f64);
|
||||
ifn!("llvm.exp.v8f64", fn(t_v8f64) -> t_v8f64);
|
||||
|
||||
ifn!("llvm.exp2.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.exp2.v2f32", fn(t_v2f32) -> t_v2f32);
|
||||
ifn!("llvm.exp2.v4f32", fn(t_v4f32) -> t_v4f32);
|
||||
ifn!("llvm.exp2.v8f32", fn(t_v8f32) -> t_v8f32);
|
||||
ifn!("llvm.exp2.v16f32", fn(t_v16f32) -> t_v16f32);
|
||||
ifn!("llvm.exp2.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.exp2.v2f64", fn(t_v2f64) -> t_v2f64);
|
||||
ifn!("llvm.exp2.v4f64", fn(t_v4f64) -> t_v4f64);
|
||||
ifn!("llvm.exp2.v8f64", fn(t_v8f64) -> t_v8f64);
|
||||
|
||||
ifn!("llvm.log.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.log.v2f32", fn(t_v2f32) -> t_v2f32);
|
||||
ifn!("llvm.log.v4f32", fn(t_v4f32) -> t_v4f32);
|
||||
ifn!("llvm.log.v8f32", fn(t_v8f32) -> t_v8f32);
|
||||
ifn!("llvm.log.v16f32", fn(t_v16f32) -> t_v16f32);
|
||||
ifn!("llvm.log.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.log.v2f64", fn(t_v2f64) -> t_v2f64);
|
||||
ifn!("llvm.log.v4f64", fn(t_v4f64) -> t_v4f64);
|
||||
ifn!("llvm.log.v8f64", fn(t_v8f64) -> t_v8f64);
|
||||
|
||||
ifn!("llvm.log10.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.log10.v2f32", fn(t_v2f32) -> t_v2f32);
|
||||
ifn!("llvm.log10.v4f32", fn(t_v4f32) -> t_v4f32);
|
||||
ifn!("llvm.log10.v8f32", fn(t_v8f32) -> t_v8f32);
|
||||
ifn!("llvm.log10.v16f32", fn(t_v16f32) -> t_v16f32);
|
||||
ifn!("llvm.log10.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.log10.v2f64", fn(t_v2f64) -> t_v2f64);
|
||||
ifn!("llvm.log10.v4f64", fn(t_v4f64) -> t_v4f64);
|
||||
ifn!("llvm.log10.v8f64", fn(t_v8f64) -> t_v8f64);
|
||||
|
||||
ifn!("llvm.log2.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.log2.v2f32", fn(t_v2f32) -> t_v2f32);
|
||||
ifn!("llvm.log2.v4f32", fn(t_v4f32) -> t_v4f32);
|
||||
ifn!("llvm.log2.v8f32", fn(t_v8f32) -> t_v8f32);
|
||||
ifn!("llvm.log2.v16f32", fn(t_v16f32) -> t_v16f32);
|
||||
ifn!("llvm.log2.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.log2.v2f64", fn(t_v2f64) -> t_v2f64);
|
||||
ifn!("llvm.log2.v4f64", fn(t_v4f64) -> t_v4f64);
|
||||
ifn!("llvm.log2.v8f64", fn(t_v8f64) -> t_v8f64);
|
||||
|
||||
ifn!("llvm.fma.f32", fn(t_f32, t_f32, t_f32) -> t_f32);
|
||||
ifn!("llvm.fma.v2f32", fn(t_v2f32, t_v2f32, t_v2f32) -> t_v2f32);
|
||||
ifn!("llvm.fma.v4f32", fn(t_v4f32, t_v4f32, t_v4f32) -> t_v4f32);
|
||||
ifn!("llvm.fma.v8f32", fn(t_v8f32, t_v8f32, t_v8f32) -> t_v8f32);
|
||||
ifn!("llvm.fma.v16f32", fn(t_v16f32, t_v16f32, t_v16f32) -> t_v16f32);
|
||||
ifn!("llvm.fma.f64", fn(t_f64, t_f64, t_f64) -> t_f64);
|
||||
ifn!("llvm.fma.v2f64", fn(t_v2f64, t_v2f64, t_v2f64) -> t_v2f64);
|
||||
ifn!("llvm.fma.v4f64", fn(t_v4f64, t_v4f64, t_v4f64) -> t_v4f64);
|
||||
ifn!("llvm.fma.v8f64", fn(t_v8f64, t_v8f64, t_v8f64) -> t_v8f64);
|
||||
|
||||
ifn!("llvm.fabs.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.fabs.v2f32", fn(t_v2f32) -> t_v2f32);
|
||||
ifn!("llvm.fabs.v4f32", fn(t_v4f32) -> t_v4f32);
|
||||
ifn!("llvm.fabs.v8f32", fn(t_v8f32) -> t_v8f32);
|
||||
ifn!("llvm.fabs.v16f32", fn(t_v16f32) -> t_v16f32);
|
||||
ifn!("llvm.fabs.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.fabs.v2f64", fn(t_v2f64) -> t_v2f64);
|
||||
ifn!("llvm.fabs.v4f64", fn(t_v4f64) -> t_v4f64);
|
||||
ifn!("llvm.fabs.v8f64", fn(t_v8f64) -> t_v8f64);
|
||||
|
||||
ifn!("llvm.minnum.f32", fn(t_f32, t_f32) -> t_f32);
|
||||
ifn!("llvm.minnum.f64", fn(t_f64, t_f64) -> t_f64);
|
||||
|
@ -665,24 +561,10 @@ impl CodegenCx<'b, 'tcx> {
|
|||
ifn!("llvm.maxnum.f64", fn(t_f64, t_f64) -> t_f64);
|
||||
|
||||
ifn!("llvm.floor.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.floor.v2f32", fn(t_v2f32) -> t_v2f32);
|
||||
ifn!("llvm.floor.v4f32", fn(t_v4f32) -> t_v4f32);
|
||||
ifn!("llvm.floor.v8f32", fn(t_v8f32) -> t_v8f32);
|
||||
ifn!("llvm.floor.v16f32", fn(t_v16f32) -> t_v16f32);
|
||||
ifn!("llvm.floor.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.floor.v2f64", fn(t_v2f64) -> t_v2f64);
|
||||
ifn!("llvm.floor.v4f64", fn(t_v4f64) -> t_v4f64);
|
||||
ifn!("llvm.floor.v8f64", fn(t_v8f64) -> t_v8f64);
|
||||
|
||||
ifn!("llvm.ceil.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.ceil.v2f32", fn(t_v2f32) -> t_v2f32);
|
||||
ifn!("llvm.ceil.v4f32", fn(t_v4f32) -> t_v4f32);
|
||||
ifn!("llvm.ceil.v8f32", fn(t_v8f32) -> t_v8f32);
|
||||
ifn!("llvm.ceil.v16f32", fn(t_v16f32) -> t_v16f32);
|
||||
ifn!("llvm.ceil.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.ceil.v2f64", fn(t_v2f64) -> t_v2f64);
|
||||
ifn!("llvm.ceil.v4f64", fn(t_v4f64) -> t_v4f64);
|
||||
ifn!("llvm.ceil.v8f64", fn(t_v8f64) -> t_v8f64);
|
||||
|
||||
ifn!("llvm.trunc.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.trunc.f64", fn(t_f64) -> t_f64);
|
||||
|
|
|
@ -30,6 +30,7 @@ fn declare_raw_fn(
|
|||
cx: &CodegenCx<'ll, '_>,
|
||||
name: &str,
|
||||
callconv: llvm::CallConv,
|
||||
unnamed: llvm::UnnamedAddr,
|
||||
ty: &'ll Type,
|
||||
) -> &'ll Value {
|
||||
debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty);
|
||||
|
@ -38,9 +39,7 @@ fn declare_raw_fn(
|
|||
};
|
||||
|
||||
llvm::SetFunctionCallConv(llfn, callconv);
|
||||
// Function addresses in Rust are never significant, allowing functions to
|
||||
// be merged.
|
||||
llvm::SetUnnamedAddress(llfn, llvm::UnnamedAddr::Global);
|
||||
llvm::SetUnnamedAddress(llfn, unnamed);
|
||||
|
||||
if cx.tcx.sess.opts.cg.no_redzone.unwrap_or(cx.tcx.sess.target.disable_redzone) {
|
||||
llvm::Attribute::NoRedZone.apply_llfn(Function, llfn);
|
||||
|
@ -68,8 +67,13 @@ impl CodegenCx<'ll, 'tcx> {
|
|||
///
|
||||
/// If there’s a value with the same name already declared, the function will
|
||||
/// update the declaration and return existing Value instead.
|
||||
pub fn declare_cfn(&self, name: &str, fn_type: &'ll Type) -> &'ll Value {
|
||||
declare_raw_fn(self, name, llvm::CCallConv, fn_type)
|
||||
pub fn declare_cfn(
|
||||
&self,
|
||||
name: &str,
|
||||
unnamed: llvm::UnnamedAddr,
|
||||
fn_type: &'ll Type,
|
||||
) -> &'ll Value {
|
||||
declare_raw_fn(self, name, llvm::CCallConv, unnamed, fn_type)
|
||||
}
|
||||
|
||||
/// Declare a Rust function.
|
||||
|
@ -79,7 +83,15 @@ impl CodegenCx<'ll, 'tcx> {
|
|||
pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> &'ll Value {
|
||||
debug!("declare_rust_fn(name={:?}, fn_abi={:?})", name, fn_abi);
|
||||
|
||||
let llfn = declare_raw_fn(self, name, fn_abi.llvm_cconv(), fn_abi.llvm_type(self));
|
||||
// Function addresses in Rust are never significant, allowing functions to
|
||||
// be merged.
|
||||
let llfn = declare_raw_fn(
|
||||
self,
|
||||
name,
|
||||
fn_abi.llvm_cconv(),
|
||||
llvm::UnnamedAddr::Global,
|
||||
fn_abi.llvm_type(self),
|
||||
);
|
||||
fn_abi.apply_attrs_llfn(self, llfn);
|
||||
llfn
|
||||
}
|
||||
|
|
|
@ -1009,7 +1009,7 @@ fn generic_simd_intrinsic(
|
|||
}
|
||||
|
||||
fn simd_simple_float_intrinsic(
|
||||
name: &str,
|
||||
name: Symbol,
|
||||
in_elem: &::rustc_middle::ty::TyS<'_>,
|
||||
in_ty: &::rustc_middle::ty::TyS<'_>,
|
||||
in_len: u64,
|
||||
|
@ -1036,93 +1036,69 @@ fn generic_simd_intrinsic(
|
|||
}
|
||||
}
|
||||
}
|
||||
let ety = match in_elem.kind() {
|
||||
ty::Float(f) if f.bit_width() == 32 => {
|
||||
if in_len < 2 || in_len > 16 {
|
||||
|
||||
let (elem_ty_str, elem_ty) = if let ty::Float(f) = in_elem.kind() {
|
||||
let elem_ty = bx.cx.type_float_from_ty(*f);
|
||||
match f.bit_width() {
|
||||
32 => ("f32", elem_ty),
|
||||
64 => ("f64", elem_ty),
|
||||
_ => {
|
||||
return_error!(
|
||||
"unsupported floating-point vector `{}` with length `{}` \
|
||||
out-of-range [2, 16]",
|
||||
in_ty,
|
||||
in_len
|
||||
"unsupported element type `{}` of floating-point vector `{}`",
|
||||
f.name_str(),
|
||||
in_ty
|
||||
);
|
||||
}
|
||||
"f32"
|
||||
}
|
||||
ty::Float(f) if f.bit_width() == 64 => {
|
||||
if in_len < 2 || in_len > 8 {
|
||||
return_error!(
|
||||
"unsupported floating-point vector `{}` with length `{}` \
|
||||
out-of-range [2, 8]",
|
||||
in_ty,
|
||||
in_len
|
||||
);
|
||||
}
|
||||
"f64"
|
||||
}
|
||||
ty::Float(f) => {
|
||||
return_error!(
|
||||
"unsupported element type `{}` of floating-point vector `{}`",
|
||||
f.name_str(),
|
||||
in_ty
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
return_error!("`{}` is not a floating-point type", in_ty);
|
||||
}
|
||||
} else {
|
||||
return_error!("`{}` is not a floating-point type", in_ty);
|
||||
};
|
||||
|
||||
let llvm_name = &format!("llvm.{0}.v{1}{2}", name, in_len, ety);
|
||||
let intrinsic = bx.get_intrinsic(&llvm_name);
|
||||
let c =
|
||||
bx.call(intrinsic, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None);
|
||||
let vec_ty = bx.type_vector(elem_ty, in_len);
|
||||
|
||||
let (intr_name, fn_ty) = match name {
|
||||
sym::simd_fsqrt => ("sqrt", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_fsin => ("sin", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_fcos => ("cos", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_fabs => ("fabs", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_floor => ("floor", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_ceil => ("ceil", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_fexp => ("exp", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_fexp2 => ("exp2", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_flog10 => ("log10", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_flog2 => ("log2", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_flog => ("log", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_fpowi => ("powi", bx.type_func(&[vec_ty, bx.type_i32()], vec_ty)),
|
||||
sym::simd_fpow => ("pow", bx.type_func(&[vec_ty, vec_ty], vec_ty)),
|
||||
sym::simd_fma => ("fma", bx.type_func(&[vec_ty, vec_ty, vec_ty], vec_ty)),
|
||||
_ => return_error!("unrecognized intrinsic `{}`", name),
|
||||
};
|
||||
|
||||
let llvm_name = &format!("llvm.{0}.v{1}{2}", intr_name, in_len, elem_ty_str);
|
||||
let f = bx.declare_cfn(&llvm_name, llvm::UnnamedAddr::No, fn_ty);
|
||||
let c = bx.call(f, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None);
|
||||
unsafe { llvm::LLVMRustSetHasUnsafeAlgebra(c) };
|
||||
Ok(c)
|
||||
}
|
||||
|
||||
match name {
|
||||
sym::simd_fsqrt => {
|
||||
return simd_simple_float_intrinsic("sqrt", in_elem, in_ty, in_len, bx, span, args);
|
||||
}
|
||||
sym::simd_fsin => {
|
||||
return simd_simple_float_intrinsic("sin", in_elem, in_ty, in_len, bx, span, args);
|
||||
}
|
||||
sym::simd_fcos => {
|
||||
return simd_simple_float_intrinsic("cos", in_elem, in_ty, in_len, bx, span, args);
|
||||
}
|
||||
sym::simd_fabs => {
|
||||
return simd_simple_float_intrinsic("fabs", in_elem, in_ty, in_len, bx, span, args);
|
||||
}
|
||||
sym::simd_floor => {
|
||||
return simd_simple_float_intrinsic("floor", in_elem, in_ty, in_len, bx, span, args);
|
||||
}
|
||||
sym::simd_ceil => {
|
||||
return simd_simple_float_intrinsic("ceil", in_elem, in_ty, in_len, bx, span, args);
|
||||
}
|
||||
sym::simd_fexp => {
|
||||
return simd_simple_float_intrinsic("exp", in_elem, in_ty, in_len, bx, span, args);
|
||||
}
|
||||
sym::simd_fexp2 => {
|
||||
return simd_simple_float_intrinsic("exp2", in_elem, in_ty, in_len, bx, span, args);
|
||||
}
|
||||
sym::simd_flog10 => {
|
||||
return simd_simple_float_intrinsic("log10", in_elem, in_ty, in_len, bx, span, args);
|
||||
}
|
||||
sym::simd_flog2 => {
|
||||
return simd_simple_float_intrinsic("log2", in_elem, in_ty, in_len, bx, span, args);
|
||||
}
|
||||
sym::simd_flog => {
|
||||
return simd_simple_float_intrinsic("log", in_elem, in_ty, in_len, bx, span, args);
|
||||
}
|
||||
sym::simd_fpowi => {
|
||||
return simd_simple_float_intrinsic("powi", in_elem, in_ty, in_len, bx, span, args);
|
||||
}
|
||||
sym::simd_fpow => {
|
||||
return simd_simple_float_intrinsic("pow", in_elem, in_ty, in_len, bx, span, args);
|
||||
}
|
||||
sym::simd_fma => {
|
||||
return simd_simple_float_intrinsic("fma", in_elem, in_ty, in_len, bx, span, args);
|
||||
}
|
||||
_ => { /* fallthrough */ }
|
||||
if std::matches!(
|
||||
name,
|
||||
sym::simd_fsqrt
|
||||
| sym::simd_fsin
|
||||
| sym::simd_fcos
|
||||
| sym::simd_fabs
|
||||
| sym::simd_floor
|
||||
| sym::simd_ceil
|
||||
| sym::simd_fexp
|
||||
| sym::simd_fexp2
|
||||
| sym::simd_flog10
|
||||
| sym::simd_flog2
|
||||
| sym::simd_flog
|
||||
| sym::simd_fpowi
|
||||
| sym::simd_fpow
|
||||
| sym::simd_fma
|
||||
) {
|
||||
return simd_simple_float_intrinsic(name, in_elem, in_ty, in_len, bx, span, args);
|
||||
}
|
||||
|
||||
// FIXME: use:
|
||||
|
@ -1278,12 +1254,12 @@ fn generic_simd_intrinsic(
|
|||
format!("llvm.masked.gather.{}.{}", llvm_elem_vec_str, llvm_pointer_vec_str);
|
||||
let f = bx.declare_cfn(
|
||||
&llvm_intrinsic,
|
||||
llvm::UnnamedAddr::No,
|
||||
bx.type_func(
|
||||
&[llvm_pointer_vec_ty, alignment_ty, mask_ty, llvm_elem_vec_ty],
|
||||
llvm_elem_vec_ty,
|
||||
),
|
||||
);
|
||||
llvm::SetUnnamedAddress(f, llvm::UnnamedAddr::No);
|
||||
let v = bx.call(f, &[args[1].immediate(), alignment, mask, args[0].immediate()], None);
|
||||
return Ok(v);
|
||||
}
|
||||
|
@ -1408,9 +1384,9 @@ fn generic_simd_intrinsic(
|
|||
format!("llvm.masked.scatter.{}.{}", llvm_elem_vec_str, llvm_pointer_vec_str);
|
||||
let f = bx.declare_cfn(
|
||||
&llvm_intrinsic,
|
||||
llvm::UnnamedAddr::No,
|
||||
bx.type_func(&[llvm_elem_vec_ty, llvm_pointer_vec_ty, alignment_ty, mask_ty], ret_t),
|
||||
);
|
||||
llvm::SetUnnamedAddress(f, llvm::UnnamedAddr::No);
|
||||
let v = bx.call(f, &[args[0].immediate(), args[1].immediate(), alignment, mask], None);
|
||||
return Ok(v);
|
||||
}
|
||||
|
@ -1714,8 +1690,11 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
|
|||
);
|
||||
let vec_ty = bx.cx.type_vector(elem_ty, in_len as u64);
|
||||
|
||||
let f = bx.declare_cfn(&llvm_intrinsic, bx.type_func(&[vec_ty, vec_ty], vec_ty));
|
||||
llvm::SetUnnamedAddress(f, llvm::UnnamedAddr::No);
|
||||
let f = bx.declare_cfn(
|
||||
&llvm_intrinsic,
|
||||
llvm::UnnamedAddr::No,
|
||||
bx.type_func(&[vec_ty, vec_ty], vec_ty),
|
||||
);
|
||||
let v = bx.call(f, &[lhs, rhs], None);
|
||||
return Ok(v);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ This will cause an error:
|
|||
#![feature(repr_simd)]
|
||||
|
||||
#[repr(simd)]
|
||||
struct Bad<T>(T, T, T);
|
||||
struct Bad<T>(T, T, T, T);
|
||||
```
|
||||
|
||||
This will not:
|
||||
|
@ -20,5 +20,5 @@ This will not:
|
|||
#![feature(repr_simd)]
|
||||
|
||||
#[repr(simd)]
|
||||
struct Good(u32, u32, u32);
|
||||
struct Good(u32, u32, u32, u32);
|
||||
```
|
||||
|
|
|
@ -7,7 +7,7 @@ Erroneous code example:
|
|||
#![feature(repr_simd)]
|
||||
|
||||
#[repr(simd)]
|
||||
struct Bad(u16, u32, u32); // error!
|
||||
struct Bad(u16, u32, u32 u32); // error!
|
||||
```
|
||||
|
||||
When using the `#[simd]` attribute to automatically use SIMD operations in tuple
|
||||
|
@ -20,5 +20,5 @@ Fixed example:
|
|||
#![feature(repr_simd)]
|
||||
|
||||
#[repr(simd)]
|
||||
struct Good(u32, u32, u32); // ok!
|
||||
struct Good(u32, u32, u32, u32); // ok!
|
||||
```
|
||||
|
|
|
@ -19,5 +19,5 @@ Fixed example:
|
|||
#![feature(repr_simd)]
|
||||
|
||||
#[repr(simd)]
|
||||
struct Good(u32, u32, u32); // ok!
|
||||
struct Good(u32, u32, u32, u32); // ok!
|
||||
```
|
||||
|
|
|
@ -188,6 +188,13 @@ pub const FAT_PTR_ADDR: usize = 0;
|
|||
/// - For a slice, this is the length.
|
||||
pub const FAT_PTR_EXTRA: usize = 1;
|
||||
|
||||
/// The maximum supported number of lanes in a SIMD vector.
|
||||
///
|
||||
/// This value is selected based on backend support:
|
||||
/// * LLVM does not appear to have a vector width limit.
|
||||
/// * Cranelift stores the base-2 log of the lane count in a 4 bit integer.
|
||||
pub const MAX_SIMD_LANES: u64 = 1 << 0xF;
|
||||
|
||||
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable)]
|
||||
pub enum LayoutError<'tcx> {
|
||||
Unknown(Ty<'tcx>),
|
||||
|
@ -717,10 +724,22 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
};
|
||||
|
||||
// SIMD vectors of zero length are not supported.
|
||||
// Additionally, lengths are capped at 2^16 as a fixed maximum backends must
|
||||
// support.
|
||||
//
|
||||
// Can't be caught in typeck if the array length is generic.
|
||||
if e_len == 0 {
|
||||
tcx.sess.fatal(&format!("monomorphising SIMD type `{}` of zero length", ty));
|
||||
} else if !e_len.is_power_of_two() {
|
||||
tcx.sess.fatal(&format!(
|
||||
"monomorphising SIMD type `{}` of non-power-of-two length",
|
||||
ty
|
||||
));
|
||||
} else if e_len > MAX_SIMD_LANES {
|
||||
tcx.sess.fatal(&format!(
|
||||
"monomorphising SIMD type `{}` of length greater than {}",
|
||||
ty, MAX_SIMD_LANES,
|
||||
));
|
||||
}
|
||||
|
||||
// Compute the ABI of the element type:
|
||||
|
|
|
@ -12,6 +12,7 @@ use rustc_hir::{ItemKind, Node};
|
|||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::layout::MAX_SIMD_LANES;
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_middle::ty::util::{Discr, IntTypeExt, Representability};
|
||||
use rustc_middle::ty::{self, ParamEnv, RegionKind, ToPredicate, Ty, TyCtxt};
|
||||
|
@ -1134,6 +1135,38 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
|
|||
.emit();
|
||||
return;
|
||||
}
|
||||
|
||||
let len = if let ty::Array(_ty, c) = e.kind() {
|
||||
c.try_eval_usize(tcx, tcx.param_env(def.did))
|
||||
} else {
|
||||
Some(fields.len() as u64)
|
||||
};
|
||||
if let Some(len) = len {
|
||||
if len == 0 {
|
||||
struct_span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty").emit();
|
||||
return;
|
||||
} else if !len.is_power_of_two() {
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
sp,
|
||||
E0075,
|
||||
"SIMD vector length must be a power of two"
|
||||
)
|
||||
.emit();
|
||||
return;
|
||||
} else if len > MAX_SIMD_LANES {
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
sp,
|
||||
E0075,
|
||||
"SIMD vector cannot have more than {} elements",
|
||||
MAX_SIMD_LANES,
|
||||
)
|
||||
.emit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
match e.kind() {
|
||||
ty::Param(_) => { /* struct<T>(T, T, T, T) is ok */ }
|
||||
_ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ }
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
#[repr(simd)] struct i8x1(i8);
|
||||
#[repr(simd)] struct u16x2(u16, u16);
|
||||
#[repr(simd)] struct f32x3(f32, f32, f32);
|
||||
#[repr(simd)] struct f32x4(f32, f32, f32, f32);
|
||||
|
||||
extern "platform-intrinsic" {
|
||||
#[rustc_const_stable(feature = "foo", since = "1.3.37")]
|
||||
|
@ -39,19 +39,23 @@ fn main() {
|
|||
assert_eq!(Y1, 42);
|
||||
}
|
||||
{
|
||||
const U: f32x3 = f32x3(13., 14., 15.);
|
||||
const V: f32x3 = unsafe { simd_insert(U, 1_u32, 42_f32) };
|
||||
const U: f32x4 = f32x4(13., 14., 15., 16.);
|
||||
const V: f32x4 = unsafe { simd_insert(U, 1_u32, 42_f32) };
|
||||
const X0: f32 = V.0;
|
||||
const X1: f32 = V.1;
|
||||
const X2: f32 = V.2;
|
||||
const X3: f32 = V.3;
|
||||
const Y0: f32 = unsafe { simd_extract(V, 0) };
|
||||
const Y1: f32 = unsafe { simd_extract(V, 1) };
|
||||
const Y2: f32 = unsafe { simd_extract(V, 2) };
|
||||
const Y3: f32 = unsafe { simd_extract(V, 3) };
|
||||
assert_eq!(X0, 13.);
|
||||
assert_eq!(X1, 42.);
|
||||
assert_eq!(X2, 15.);
|
||||
assert_eq!(X3, 16.);
|
||||
assert_eq!(Y0, 13.);
|
||||
assert_eq!(Y1, 42.);
|
||||
assert_eq!(Y2, 15.);
|
||||
assert_eq!(Y3, 16.);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,10 +9,6 @@ struct i32x2(i32, i32);
|
|||
#[repr(simd)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
struct i32x3(i32, i32, i32);
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
struct i32x4(i32, i32, i32, i32);
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone)]
|
||||
|
@ -27,10 +23,6 @@ struct f32x2(f32, f32);
|
|||
#[repr(simd)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
struct f32x3(f32, f32, f32);
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
struct f32x4(f32, f32, f32, f32);
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone)]
|
||||
|
@ -43,7 +35,6 @@ extern "platform-intrinsic" {
|
|||
fn simd_extract<T, E>(x: T, idx: u32) -> E;
|
||||
|
||||
fn simd_shuffle2<T, U>(x: T, y: T, idx: [u32; 2]) -> U;
|
||||
fn simd_shuffle3<T, U>(x: T, y: T, idx: [u32; 3]) -> U;
|
||||
fn simd_shuffle4<T, U>(x: T, y: T, idx: [u32; 4]) -> U;
|
||||
fn simd_shuffle8<T, U>(x: T, y: T, idx: [u32; 8]) -> U;
|
||||
}
|
||||
|
@ -61,8 +52,6 @@ fn main() {
|
|||
|
||||
simd_shuffle2::<i32, i32>(0, 0, [0; 2]);
|
||||
//~^ ERROR expected SIMD input type, found non-SIMD `i32`
|
||||
simd_shuffle3::<i32, i32>(0, 0, [0; 3]);
|
||||
//~^ ERROR expected SIMD input type, found non-SIMD `i32`
|
||||
simd_shuffle4::<i32, i32>(0, 0, [0; 4]);
|
||||
//~^ ERROR expected SIMD input type, found non-SIMD `i32`
|
||||
simd_shuffle8::<i32, i32>(0, 0, [0; 8]);
|
||||
|
@ -70,8 +59,6 @@ fn main() {
|
|||
|
||||
simd_shuffle2::<_, f32x2>(x, x, [0; 2]);
|
||||
//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32`
|
||||
simd_shuffle3::<_, f32x3>(x, x, [0; 3]);
|
||||
//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x3` with element type `f32`
|
||||
simd_shuffle4::<_, f32x4>(x, x, [0; 4]);
|
||||
//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32`
|
||||
simd_shuffle8::<_, f32x8>(x, x, [0; 8]);
|
||||
|
@ -79,10 +66,8 @@ fn main() {
|
|||
|
||||
simd_shuffle2::<_, i32x8>(x, x, [0; 2]);
|
||||
//~^ ERROR expected return type of length 2, found `i32x8` with length 8
|
||||
simd_shuffle3::<_, i32x4>(x, x, [0; 3]);
|
||||
//~^ ERROR expected return type of length 3, found `i32x4` with length 4
|
||||
simd_shuffle4::<_, i32x3>(x, x, [0; 4]);
|
||||
//~^ ERROR expected return type of length 4, found `i32x3` with length 3
|
||||
simd_shuffle4::<_, i32x8>(x, x, [0; 4]);
|
||||
//~^ ERROR expected return type of length 4, found `i32x8` with length 8
|
||||
simd_shuffle8::<_, i32x2>(x, x, [0; 8]);
|
||||
//~^ ERROR expected return type of length 8, found `i32x2` with length 2
|
||||
}
|
||||
|
|
|
@ -1,93 +1,75 @@
|
|||
error[E0511]: invalid monomorphization of `simd_insert` intrinsic: expected SIMD input type, found non-SIMD `i32`
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:55:9
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:46:9
|
||||
|
|
||||
LL | simd_insert(0, 0, 0);
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0511]: invalid monomorphization of `simd_insert` intrinsic: expected inserted type `i32` (element of input `i32x4`), found `f64`
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:57:9
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:48:9
|
||||
|
|
||||
LL | simd_insert(x, 0, 1.0);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0511]: invalid monomorphization of `simd_extract` intrinsic: expected return type `i32` (element of input `i32x4`), found `f32`
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:59:9
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:50:9
|
||||
|
|
||||
LL | simd_extract::<_, f32>(x, 0);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: expected SIMD input type, found non-SIMD `i32`
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:62:9
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:53:9
|
||||
|
|
||||
LL | simd_shuffle2::<i32, i32>(0, 0, [0; 2]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0511]: invalid monomorphization of `simd_shuffle3` intrinsic: expected SIMD input type, found non-SIMD `i32`
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:64:9
|
||||
|
|
||||
LL | simd_shuffle3::<i32, i32>(0, 0, [0; 3]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: expected SIMD input type, found non-SIMD `i32`
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:66:9
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:55:9
|
||||
|
|
||||
LL | simd_shuffle4::<i32, i32>(0, 0, [0; 4]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: expected SIMD input type, found non-SIMD `i32`
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:68:9
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:57:9
|
||||
|
|
||||
LL | simd_shuffle8::<i32, i32>(0, 0, [0; 8]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32`
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:71:9
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:60:9
|
||||
|
|
||||
LL | simd_shuffle2::<_, f32x2>(x, x, [0; 2]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0511]: invalid monomorphization of `simd_shuffle3` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x3` with element type `f32`
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:73:9
|
||||
|
|
||||
LL | simd_shuffle3::<_, f32x3>(x, x, [0; 3]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32`
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:75:9
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:62:9
|
||||
|
|
||||
LL | simd_shuffle4::<_, f32x4>(x, x, [0; 4]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32`
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:77:9
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:64:9
|
||||
|
|
||||
LL | simd_shuffle8::<_, f32x8>(x, x, [0; 8]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: expected return type of length 2, found `i32x8` with length 8
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:80:9
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:67:9
|
||||
|
|
||||
LL | simd_shuffle2::<_, i32x8>(x, x, [0; 2]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0511]: invalid monomorphization of `simd_shuffle3` intrinsic: expected return type of length 3, found `i32x4` with length 4
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:82:9
|
||||
error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: expected return type of length 4, found `i32x8` with length 8
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:69:9
|
||||
|
|
||||
LL | simd_shuffle3::<_, i32x4>(x, x, [0; 3]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: expected return type of length 4, found `i32x3` with length 3
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:84:9
|
||||
|
|
||||
LL | simd_shuffle4::<_, i32x3>(x, x, [0; 4]);
|
||||
LL | simd_shuffle4::<_, i32x8>(x, x, [0; 4]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: expected return type of length 8, found `i32x2` with length 2
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:86:9
|
||||
--> $DIR/simd-intrinsic-generic-elements.rs:71:9
|
||||
|
|
||||
LL | simd_shuffle8::<_, i32x2>(x, x, [0; 8]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 15 previous errors
|
||||
error: aborting due to 12 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0511`.
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
#![feature(repr_simd)]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
// ignore-tidy-linelength
|
||||
|
||||
#[repr(simd)]
|
||||
struct empty; //~ ERROR SIMD vector cannot be empty
|
||||
|
||||
#[repr(simd)]
|
||||
struct i64f64(i64, f64); //~ ERROR SIMD vector should be homogeneous
|
||||
|
||||
struct Foo;
|
||||
|
||||
#[repr(simd)]
|
||||
struct FooV(Foo, Foo); //~ ERROR SIMD vector element type should be a primitive scalar (integer/float/pointer) type
|
||||
|
||||
#[repr(simd)]
|
||||
struct FooV2([Foo; 2]); //~ ERROR SIMD vector element type should be a primitive scalar (integer/float/pointer) type
|
||||
|
||||
fn main() {}
|
|
@ -1,8 +1,8 @@
|
|||
// run-pass
|
||||
#![feature(repr_simd)]
|
||||
|
||||
#[repr(simd)]
|
||||
struct T(f64, f64, f64);
|
||||
//~^ ERROR SIMD vector length must be a power of two
|
||||
|
||||
static X: T = T(0.0, 0.0, 0.0);
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
error[E0075]: SIMD vector length must be a power of two
|
||||
--> $DIR/issue-17170.rs:4:1
|
||||
|
|
||||
LL | struct T(f64, f64, f64);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: monomorphising SIMD type `T` of non-power-of-two length
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0075`.
|
|
@ -1,4 +1,3 @@
|
|||
// run-pass
|
||||
// ignore-emscripten FIXME(#45351)
|
||||
|
||||
#![feature(repr_simd, platform_intrinsics)]
|
||||
|
@ -6,10 +5,12 @@
|
|||
#[repr(simd)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Char3(pub i8, pub i8, pub i8);
|
||||
//~^ ERROR SIMD vector length must be a power of two
|
||||
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Short3(pub i16, pub i16, pub i16);
|
||||
//~^ ERROR SIMD vector length must be a power of two
|
||||
|
||||
extern "platform-intrinsic" {
|
||||
fn simd_cast<T, U>(x: T) -> U;
|
|
@ -0,0 +1,15 @@
|
|||
error[E0075]: SIMD vector length must be a power of two
|
||||
--> $DIR/issue-39720.rs:7:1
|
||||
|
|
||||
LL | pub struct Char3(pub i8, pub i8, pub i8);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0075]: SIMD vector length must be a power of two
|
||||
--> $DIR/issue-39720.rs:12:1
|
||||
|
|
||||
LL | pub struct Short3(pub i16, pub i16, pub i16);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0075`.
|
|
@ -10,10 +10,6 @@ struct i32x2(i32, i32);
|
|||
#[repr(simd)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
#[allow(non_camel_case_types)]
|
||||
struct i32x3(i32, i32, i32);
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
#[allow(non_camel_case_types)]
|
||||
struct i32x4(i32, i32, i32, i32);
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
|
@ -26,7 +22,6 @@ extern "platform-intrinsic" {
|
|||
fn simd_extract<T, E>(x: T, idx: u32) -> E;
|
||||
|
||||
fn simd_shuffle2<T, U>(x: T, y: T, idx: [u32; 2]) -> U;
|
||||
fn simd_shuffle3<T, U>(x: T, y: T, idx: [u32; 3]) -> U;
|
||||
fn simd_shuffle4<T, U>(x: T, y: T, idx: [u32; 4]) -> U;
|
||||
fn simd_shuffle8<T, U>(x: T, y: T, idx: [u32; 8]) -> U;
|
||||
}
|
||||
|
@ -45,17 +40,12 @@ macro_rules! all_eq {
|
|||
|
||||
fn main() {
|
||||
let x2 = i32x2(20, 21);
|
||||
let x3 = i32x3(30, 31, 32);
|
||||
let x4 = i32x4(40, 41, 42, 43);
|
||||
let x8 = i32x8(80, 81, 82, 83, 84, 85, 86, 87);
|
||||
unsafe {
|
||||
all_eq!(simd_insert(x2, 0, 100), i32x2(100, 21));
|
||||
all_eq!(simd_insert(x2, 1, 100), i32x2(20, 100));
|
||||
|
||||
all_eq!(simd_insert(x3, 0, 100), i32x3(100, 31, 32));
|
||||
all_eq!(simd_insert(x3, 1, 100), i32x3(30, 100, 32));
|
||||
all_eq!(simd_insert(x3, 2, 100), i32x3(30, 31, 100));
|
||||
|
||||
all_eq!(simd_insert(x4, 0, 100), i32x4(100, 41, 42, 43));
|
||||
all_eq!(simd_insert(x4, 1, 100), i32x4(40, 100, 42, 43));
|
||||
all_eq!(simd_insert(x4, 2, 100), i32x4(40, 41, 100, 43));
|
||||
|
@ -73,10 +63,6 @@ fn main() {
|
|||
all_eq!(simd_extract(x2, 0), 20);
|
||||
all_eq!(simd_extract(x2, 1), 21);
|
||||
|
||||
all_eq!(simd_extract(x3, 0), 30);
|
||||
all_eq!(simd_extract(x3, 1), 31);
|
||||
all_eq!(simd_extract(x3, 2), 32);
|
||||
|
||||
all_eq!(simd_extract(x4, 0), 40);
|
||||
all_eq!(simd_extract(x4, 1), 41);
|
||||
all_eq!(simd_extract(x4, 2), 42);
|
||||
|
@ -93,30 +79,20 @@ fn main() {
|
|||
}
|
||||
|
||||
let y2 = i32x2(120, 121);
|
||||
let y3 = i32x3(130, 131, 132);
|
||||
let y4 = i32x4(140, 141, 142, 143);
|
||||
let y8 = i32x8(180, 181, 182, 183, 184, 185, 186, 187);
|
||||
unsafe {
|
||||
all_eq!(simd_shuffle2(x2, y2, [3, 0]), i32x2(121, 20));
|
||||
all_eq!(simd_shuffle3(x2, y2, [3, 0, 1]), i32x3(121, 20, 21));
|
||||
all_eq!(simd_shuffle4(x2, y2, [3, 0, 1, 2]), i32x4(121, 20, 21, 120));
|
||||
all_eq!(simd_shuffle8(x2, y2, [3, 0, 1, 2, 1, 2, 3, 0]),
|
||||
i32x8(121, 20, 21, 120, 21, 120, 121, 20));
|
||||
|
||||
all_eq!(simd_shuffle2(x3, y3, [4, 2]), i32x2(131, 32));
|
||||
all_eq!(simd_shuffle3(x3, y3, [4, 2, 3]), i32x3(131, 32, 130));
|
||||
all_eq!(simd_shuffle4(x3, y3, [4, 2, 3, 0]), i32x4(131, 32, 130, 30));
|
||||
all_eq!(simd_shuffle8(x3, y3, [4, 2, 3, 0, 1, 5, 5, 1]),
|
||||
i32x8(131, 32, 130, 30, 31, 132, 132, 31));
|
||||
|
||||
all_eq!(simd_shuffle2(x4, y4, [7, 2]), i32x2(143, 42));
|
||||
all_eq!(simd_shuffle3(x4, y4, [7, 2, 5]), i32x3(143, 42, 141));
|
||||
all_eq!(simd_shuffle4(x4, y4, [7, 2, 5, 0]), i32x4(143, 42, 141, 40));
|
||||
all_eq!(simd_shuffle8(x4, y4, [7, 2, 5, 0, 3, 6, 4, 1]),
|
||||
i32x8(143, 42, 141, 40, 43, 142, 140, 41));
|
||||
|
||||
all_eq!(simd_shuffle2(x8, y8, [11, 5]), i32x2(183, 85));
|
||||
all_eq!(simd_shuffle3(x8, y8, [11, 5, 15]), i32x3(183, 85, 187));
|
||||
all_eq!(simd_shuffle4(x8, y8, [11, 5, 15, 0]), i32x4(183, 85, 187, 80));
|
||||
all_eq!(simd_shuffle8(x8, y8, [11, 5, 15, 0, 3, 8, 12, 1]),
|
||||
i32x8(183, 85, 187, 80, 83, 180, 184, 81));
|
||||
|
|
|
@ -10,87 +10,44 @@ use std::mem;
|
|||
/// `T` should satisfy `size_of T (mod min_align_of T) === 0` to be stored at `Vec<T>` properly
|
||||
/// Please consult the issue #20460
|
||||
fn check<T>() {
|
||||
assert_eq!(mem::size_of::<T>() % mem::min_align_of::<T>(), 0)
|
||||
assert_eq!(mem::size_of::<T>() % mem::min_align_of::<T>(), 0);
|
||||
assert_eq!(mem::size_of::<T>() % mem::min_align_of::<T>(), 0);
|
||||
assert_eq!(mem::size_of::<T>() % mem::min_align_of::<T>(), 0);
|
||||
}
|
||||
|
||||
#[repr(simd)]
|
||||
struct U8<const N: usize>([u8; N]);
|
||||
|
||||
#[repr(simd)]
|
||||
struct I16<const N: usize>([i16; N]);
|
||||
|
||||
#[repr(simd)]
|
||||
struct F32<const N: usize>([f32; N]);
|
||||
|
||||
#[repr(simd)]
|
||||
struct Usize<const N: usize>([usize; N]);
|
||||
|
||||
#[repr(simd)]
|
||||
struct Isize<const N: usize>([isize; N]);
|
||||
|
||||
fn main() {
|
||||
check::<u8x2>();
|
||||
check::<u8x3>();
|
||||
check::<u8x4>();
|
||||
check::<u8x5>();
|
||||
check::<u8x6>();
|
||||
check::<u8x7>();
|
||||
check::<u8x8>();
|
||||
check::<U8<2>>();
|
||||
check::<U8<4>>();
|
||||
check::<U8<8>>();
|
||||
|
||||
check::<i16x2>();
|
||||
check::<i16x3>();
|
||||
check::<i16x4>();
|
||||
check::<i16x5>();
|
||||
check::<i16x6>();
|
||||
check::<i16x7>();
|
||||
check::<i16x8>();
|
||||
check::<I16<2>>();
|
||||
check::<I16<4>>();
|
||||
check::<I16<8>>();
|
||||
|
||||
check::<f32x2>();
|
||||
check::<f32x3>();
|
||||
check::<f32x4>();
|
||||
check::<f32x5>();
|
||||
check::<f32x6>();
|
||||
check::<f32x7>();
|
||||
check::<f32x8>();
|
||||
check::<F32<2>>();
|
||||
check::<F32<4>>();
|
||||
check::<F32<8>>();
|
||||
|
||||
check::<usizex2>();
|
||||
check::<usizex3>();
|
||||
check::<usizex4>();
|
||||
check::<usizex5>();
|
||||
check::<usizex6>();
|
||||
check::<usizex7>();
|
||||
check::<usizex8>();
|
||||
check::<Usize<2>>();
|
||||
check::<Usize<4>>();
|
||||
check::<Usize<8>>();
|
||||
|
||||
check::<isizex2>();
|
||||
check::<isizex3>();
|
||||
check::<isizex4>();
|
||||
check::<isizex5>();
|
||||
check::<isizex6>();
|
||||
check::<isizex7>();
|
||||
check::<isizex8>();
|
||||
check::<Isize<2>>();
|
||||
check::<Isize<4>>();
|
||||
check::<Isize<8>>();
|
||||
}
|
||||
|
||||
#[repr(simd)] struct u8x2(u8, u8);
|
||||
#[repr(simd)] struct u8x3(u8, u8, u8);
|
||||
#[repr(simd)] struct u8x4(u8, u8, u8, u8);
|
||||
#[repr(simd)] struct u8x5(u8, u8, u8, u8, u8);
|
||||
#[repr(simd)] struct u8x6(u8, u8, u8, u8, u8, u8);
|
||||
#[repr(simd)] struct u8x7(u8, u8, u8, u8, u8, u8, u8);
|
||||
#[repr(simd)] struct u8x8(u8, u8, u8, u8, u8, u8, u8, u8);
|
||||
|
||||
#[repr(simd)] struct i16x2(i16, i16);
|
||||
#[repr(simd)] struct i16x3(i16, i16, i16);
|
||||
#[repr(simd)] struct i16x4(i16, i16, i16, i16);
|
||||
#[repr(simd)] struct i16x5(i16, i16, i16, i16, i16);
|
||||
#[repr(simd)] struct i16x6(i16, i16, i16, i16, i16, i16);
|
||||
#[repr(simd)] struct i16x7(i16, i16, i16, i16, i16, i16, i16);
|
||||
#[repr(simd)] struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16);
|
||||
|
||||
#[repr(simd)] struct f32x2(f32, f32);
|
||||
#[repr(simd)] struct f32x3(f32, f32, f32);
|
||||
#[repr(simd)] struct f32x4(f32, f32, f32, f32);
|
||||
#[repr(simd)] struct f32x5(f32, f32, f32, f32, f32);
|
||||
#[repr(simd)] struct f32x6(f32, f32, f32, f32, f32, f32);
|
||||
#[repr(simd)] struct f32x7(f32, f32, f32, f32, f32, f32, f32);
|
||||
#[repr(simd)] struct f32x8(f32, f32, f32, f32, f32, f32, f32, f32);
|
||||
|
||||
#[repr(simd)] struct usizex2(usize, usize);
|
||||
#[repr(simd)] struct usizex3(usize, usize, usize);
|
||||
#[repr(simd)] struct usizex4(usize, usize, usize, usize);
|
||||
#[repr(simd)] struct usizex5(usize, usize, usize, usize, usize);
|
||||
#[repr(simd)] struct usizex6(usize, usize, usize, usize, usize, usize);
|
||||
#[repr(simd)] struct usizex7(usize, usize, usize, usize, usize, usize, usize);
|
||||
#[repr(simd)] struct usizex8(usize, usize, usize, usize, usize, usize, usize, usize);
|
||||
|
||||
#[repr(simd)] struct isizex2(isize, isize);
|
||||
#[repr(simd)] struct isizex3(isize, isize, isize);
|
||||
#[repr(simd)] struct isizex4(isize, isize, isize, isize);
|
||||
#[repr(simd)] struct isizex5(isize, isize, isize, isize, isize);
|
||||
#[repr(simd)] struct isizex6(isize, isize, isize, isize, isize, isize);
|
||||
#[repr(simd)] struct isizex7(isize, isize, isize, isize, isize, isize, isize);
|
||||
#[repr(simd)] struct isizex8(isize, isize, isize, isize, isize, isize, isize, isize);
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
// build-fail
|
||||
|
||||
#![feature(repr_simd, platform_intrinsics)]
|
||||
|
||||
// error-pattern:monomorphising SIMD type `Simd<0_usize>` of zero length
|
||||
|
||||
#[repr(simd)]
|
||||
struct Simd<const N: usize>([f32; N]);
|
||||
|
||||
fn main() {
|
||||
let _ = Simd::<0>([]);
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
error: monomorphising SIMD type `Simd<0_usize>` of zero length
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// build-fail
|
||||
|
||||
#![feature(repr_simd, platform_intrinsics)]
|
||||
|
||||
// error-pattern:monomorphising SIMD type `Simd<65536_usize>` of length greater than 32768
|
||||
|
||||
#[repr(simd)]
|
||||
struct Simd<const N: usize>([f32; N]);
|
||||
|
||||
fn main() {
|
||||
let _ = Simd::<65536>([0.; 65536]);
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
error: monomorphising SIMD type `Simd<65536_usize>` of length greater than 32768
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// build-fail
|
||||
|
||||
#![feature(repr_simd, platform_intrinsics)]
|
||||
|
||||
// error-pattern:monomorphising SIMD type `Simd<3_usize>` of non-power-of-two length
|
||||
|
||||
#[repr(simd)]
|
||||
struct Simd<const N: usize>([f32; N]);
|
||||
|
||||
fn main() {
|
||||
let _ = Simd::<3>([0.; 3]);
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
error: monomorphising SIMD type `Simd<3_usize>` of non-power-of-two length
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -1,9 +1,33 @@
|
|||
// run-pass
|
||||
#![allow(dead_code)]
|
||||
|
||||
// pretty-expanded FIXME #23616
|
||||
|
||||
#![feature(repr_simd)]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
// ignore-tidy-linelength
|
||||
|
||||
#[repr(simd)]
|
||||
struct empty; //~ ERROR SIMD vector cannot be empty
|
||||
|
||||
#[repr(simd)]
|
||||
struct empty2([f32; 0]); //~ ERROR SIMD vector cannot be empty
|
||||
|
||||
#[repr(simd)]
|
||||
struct pow2([f32; 7]); //~ ERROR SIMD vector length must be a power of two
|
||||
|
||||
#[repr(simd)]
|
||||
struct i64f64(i64, f64); //~ ERROR SIMD vector should be homogeneous
|
||||
|
||||
struct Foo;
|
||||
|
||||
#[repr(simd)]
|
||||
struct FooV(Foo, Foo); //~ ERROR SIMD vector element type should be a primitive scalar (integer/float/pointer) type
|
||||
|
||||
#[repr(simd)]
|
||||
struct FooV2([Foo; 2]); //~ ERROR SIMD vector element type should be a primitive scalar (integer/float/pointer) type
|
||||
|
||||
#[repr(simd)]
|
||||
struct TooBig([f32; 65536]); //~ ERROR SIMD vector cannot have more than 32768 elements
|
||||
|
||||
#[repr(simd)]
|
||||
struct JustRight([u128; 32768]);
|
||||
|
||||
#[repr(simd)]
|
||||
struct RGBA {
|
||||
|
@ -13,4 +37,4 @@ struct RGBA {
|
|||
a: f32
|
||||
}
|
||||
|
||||
pub fn main() {}
|
||||
fn main() {}
|
||||
|
|
|
@ -4,25 +4,43 @@ error[E0075]: SIMD vector cannot be empty
|
|||
LL | struct empty;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error[E0076]: SIMD vector should be homogeneous
|
||||
error[E0075]: SIMD vector cannot be empty
|
||||
--> $DIR/simd-type.rs:10:1
|
||||
|
|
||||
LL | struct empty2([f32; 0]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0075]: SIMD vector length must be a power of two
|
||||
--> $DIR/simd-type.rs:13:1
|
||||
|
|
||||
LL | struct pow2([f32; 7]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0076]: SIMD vector should be homogeneous
|
||||
--> $DIR/simd-type.rs:16:1
|
||||
|
|
||||
LL | struct i64f64(i64, f64);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ SIMD elements must have the same type
|
||||
|
||||
error[E0077]: SIMD vector element type should be a primitive scalar (integer/float/pointer) type
|
||||
--> $DIR/simd-type.rs:15:1
|
||||
--> $DIR/simd-type.rs:21:1
|
||||
|
|
||||
LL | struct FooV(Foo, Foo);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0077]: SIMD vector element type should be a primitive scalar (integer/float/pointer) type
|
||||
--> $DIR/simd-type.rs:18:1
|
||||
--> $DIR/simd-type.rs:24:1
|
||||
|
|
||||
LL | struct FooV2([Foo; 2]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error[E0075]: SIMD vector cannot have more than 32768 elements
|
||||
--> $DIR/simd-type.rs:27:1
|
||||
|
|
||||
LL | struct TooBig([f32; 65536]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0075, E0076, E0077.
|
||||
For more information about an error, try `rustc --explain E0075`.
|
Loading…
Reference in New Issue