diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 197dd7f9c9e59..096fae5278a21 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -383,6 +383,7 @@ where hide_niches(b); } Abi::Vector { element, count: _ } => hide_niches(element), + Abi::ScalableVector { element, .. } => hide_niches(element), Abi::Aggregate { sized: _ } => {} } st.largest_niche = None; diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 52ec41f643c0d..a5b01ecbb7e6b 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -47,9 +47,11 @@ bitflags! { // If true, the type's layout can be randomized using // the seed stored in `ReprOptions.field_shuffle_seed` const RANDOMIZE_LAYOUT = 1 << 4; + const IS_SCALABLE = 1 << 5; // Any of these flags being set prevent field reordering optimisation. const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits() | ReprFlags::IS_SIMD.bits() + | ReprFlags::IS_SCALABLE.bits() | ReprFlags::IS_LINEAR.bits(); } } @@ -90,6 +92,7 @@ pub struct ReprOptions { pub align: Option, pub pack: Option, pub flags: ReprFlags, + pub scalable: Option, /// The seed to be used for randomizing a type's layout /// /// Note: This could technically be a `u128` which would @@ -106,6 +109,11 @@ impl ReprOptions { self.flags.contains(ReprFlags::IS_SIMD) } + #[inline] + pub fn scalable(&self) -> bool { + self.flags.contains(ReprFlags::IS_SCALABLE) + } + #[inline] pub fn c(&self) -> bool { self.flags.contains(ReprFlags::IS_C) @@ -1306,6 +1314,10 @@ pub enum Abi { Uninhabited, Scalar(Scalar), ScalarPair(Scalar, Scalar), + ScalableVector { + element: Scalar, + elt: u64, + }, Vector { element: Scalar, count: u64, @@ -1323,6 +1335,7 @@ impl Abi { match *self { Abi::Uninhabited | Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false, Abi::Aggregate { sized } => !sized, + Abi::ScalableVector { .. } => true, } } @@ -1369,7 +1382,7 @@ impl Abi { Abi::Vector { element, count } => { cx.data_layout().vector_align(element.size(cx) * count) } - Abi::Uninhabited | Abi::Aggregate { .. } => return None, + Abi::Uninhabited | Abi::Aggregate { .. } | Abi::ScalableVector { .. } => return None, }) } @@ -1390,7 +1403,7 @@ impl Abi { // to make the size a multiple of align (e.g. for vectors of size 3). (element.size(cx) * count).align_to(self.inherent_align(cx)?.abi) } - Abi::Uninhabited | Abi::Aggregate { .. } => return None, + Abi::Uninhabited | Abi::Aggregate { .. } | Abi::ScalableVector { .. } => return None, }) } @@ -1400,6 +1413,9 @@ impl Abi { Abi::Scalar(s) => Abi::Scalar(s.to_union()), Abi::ScalarPair(s1, s2) => Abi::ScalarPair(s1.to_union(), s2.to_union()), Abi::Vector { element, count } => Abi::Vector { element: element.to_union(), count }, + Abi::ScalableVector { element, elt } => { + Abi::ScalableVector { element: element.to_union(), elt } + } Abi::Uninhabited | Abi::Aggregate { .. } => Abi::Aggregate { sized: true }, } } @@ -1686,6 +1702,11 @@ impl LayoutS { self.is_sized() && self.size.bytes() == 0 && self.align.abi.bytes() == 1 } + /// Returns true if the size of the type is only known at runtime. + pub fn is_runtime_sized(&self) -> bool { + matches!(self.abi, Abi::ScalableVector { .. }) + } + /// Returns `true` if the type is a ZST and not unsized. /// /// Note that this does *not* imply that the type is irrelevant for layout! It can still have @@ -1695,6 +1716,7 @@ impl LayoutS { Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false, Abi::Uninhabited => self.size.bytes() == 0, Abi::Aggregate { sized } => sized && self.size.bytes() == 0, + Abi::ScalableVector { .. } => false, } } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index e91dfb2776662..0e1a5e7538919 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -267,6 +267,15 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { "SIMD types are experimental and possibly buggy" ); } + + if item.has_name(sym::scalable) { + gate!( + &self, + repr_scalable, + attr.span, + "Scalable SIMD types are experimental and possibly buggy" + ); + } } } } diff --git a/compiler/rustc_attr/messages.ftl b/compiler/rustc_attr/messages.ftl index eb51e568f81a7..c38b31c98e41b 100644 --- a/compiler/rustc_attr/messages.ftl +++ b/compiler/rustc_attr/messages.ftl @@ -94,6 +94,9 @@ attr_rustc_allowed_unstable_pairing = attr_rustc_promotable_pairing = `rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute +attr_scalable_missing_n = + invalid `scalable(num)` attribute: `scalable` needs an argument + .suggestion = supply an argument here attr_soft_no_args = `soft` should not have any arguments diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 34c24a26f7b13..353f72a86c5f2 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -918,6 +918,7 @@ pub enum ReprAttr { ReprSimd, ReprTransparent, ReprAlign(Align), + ReprScalable(u32), } #[derive(Eq, PartialEq, Debug, Copy, Clone)] @@ -973,6 +974,13 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec { recognised = true; None } + sym::scalable => { + sess.dcx().emit_err(session_diagnostics::ScalableAttrMissingN { + span: item.span(), + }); + recognised = true; + None + } name => int_type_of_word(name).map(ReprInt), }; @@ -1001,6 +1009,12 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec { literal_error = Some(message) } }; + } else if name == sym::scalable { + recognised = true; + match parse_scalable(&value.kind) { + Ok(literal) => acc.push(ReprScalable(literal)), + Err(message) => literal_error = Some(message), + }; } else if matches!(name, sym::Rust | sym::C | sym::simd | sym::transparent) || int_type_of_word(name).is_some() { @@ -1020,7 +1034,10 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec { } else if let Some(meta_item) = item.meta_item() { match &meta_item.kind { MetaItemKind::NameValue(value) => { - if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) { + if meta_item.has_name(sym::align) + || meta_item.has_name(sym::packed) + || meta_item.has_name(sym::scalable) + { let name = meta_item.name_or_empty().to_ident_string(); recognised = true; sess.dcx().emit_err(session_diagnostics::IncorrectReprFormatGeneric { @@ -1239,3 +1256,11 @@ pub fn parse_confusables(attr: &Attribute) -> Option> { return Some(candidates); } + +pub fn parse_scalable(node: &ast::LitKind) -> Result { + if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node { + (literal.get()).try_into().map_err(|_| "integer too large") + } else { + Err("not an unsuffixed integer") + } +} diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index 0cffeed0a7550..7501a08b5d509 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -401,3 +401,11 @@ pub(crate) struct UnknownVersionLiteral { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(attr_scalable_missing_n, code = E0799)] +pub(crate) struct ScalableAttrMissingN { + #[primary_span] + #[suggestion(applicability = "has-placeholders", code = "scalable(...)")] + pub span: Span, +} diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index db4b5209145f0..7c9ed607b2048 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -522,7 +522,15 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { place_ty = self.sanitize_projection(place_ty, elem, place, location, context); } - if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { + // The Copy trait isn't implemented for scalable SIMD types. + // These types live somewhere between `Sized` and `Unsize`. + // The bounds on `Copy` disallow the trait from being + // implemented for them. As a result of this no bounds from + // `Copy` apply for the type, therefore, skipping this check + // should be perfectly legal. + if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context + && !place_ty.ty.is_scalable_simd() + { let tcx = self.tcx(); let trait_ref = ty::TraitRef::new( tcx, @@ -1267,7 +1275,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } self.check_rvalue(body, rv, location); - if !self.unsized_feature_enabled() { + if !(self.unsized_feature_enabled() || place_ty.is_scalable_simd()) { let trait_ref = ty::TraitRef::new( tcx, tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), @@ -1788,7 +1796,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if !self.unsized_feature_enabled() { let span = local_decl.source_info.span; let ty = local_decl.ty; - self.ensure_place_sized(ty, span); + if !ty.is_scalable_simd() { + self.ensure_place_sized(ty, span); + } } } @@ -1804,11 +1814,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // expressions evaluate through `as_temp` or `into` a return // slot or local, so to find all unsized rvalues it is enough // to check all temps, return slots and locals. - if self.reported_errors.replace((ty, span)).is_none() { - // While this is located in `nll::typeck` this error is not - // an NLL error, it's a required check to prevent creation - // of unsized rvalues in a call expression. - self.tcx().dcx().emit_err(MoveUnsized { ty, span }); + if !ty.is_scalable_simd() { + if self.reported_errors.replace((ty, span)).is_none() { + // While this is located in `nll::typeck` this error is not + // an NLL error, it's a required check to prevent creation + // of unsized rvalues in a call expression. + self.tcx().dcx().emit_err(MoveUnsized { ty, span }); + } } } } diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index 0a99e7213be56..da5e1feecc126 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -87,6 +87,7 @@ impl GccType for Reg { _ => bug!("unsupported float: {:?}", self), }, RegKind::Vector => unimplemented!(), //cx.type_vector(cx.type_i8(), self.size.bytes()), + RegKind::ScalableVector => unimplemented!(), } } } diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 9352a67e362fb..5fe2e3d81e063 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -303,7 +303,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { let layout = self.layout_of(tp_ty).layout; let _use_integer_compare = match layout.abi() { Scalar(_) | ScalarPair(_, _) => true, - Uninhabited | Vector { .. } => false, + Uninhabited | Vector { .. } | ScalableVector { .. } => false, Aggregate { .. } => { // For rusty ABIs, small aggregates are actually passed // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index d85ed4f12ffab..83d7e8495171a 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -81,6 +81,7 @@ fn uncached_gcc_type<'gcc, 'tcx>( false, ); } + Abi::ScalableVector { .. } => todo!(), Abi::Uninhabited | Abi::Aggregate { .. } => {} } @@ -175,7 +176,7 @@ pub trait LayoutGccExt<'tcx> { impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { fn is_gcc_immediate(&self) -> bool { match self.abi { - Abi::Scalar(_) | Abi::Vector { .. } => true, + Abi::Scalar(_) | Abi::Vector { .. } | Abi::ScalableVector { .. } => true, Abi::ScalarPair(..) | Abi::Uninhabited | Abi::Aggregate { .. } => false, } } @@ -183,7 +184,11 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { fn is_gcc_scalar_pair(&self) -> bool { match self.abi { Abi::ScalarPair(..) => true, - Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } | Abi::Aggregate { .. } => false, + Abi::Uninhabited + | Abi::Scalar(_) + | Abi::Vector { .. } + | Abi::ScalableVector { .. } + | Abi::Aggregate { .. } => false, } } diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index d034f9b525690..e148f00ded512 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -126,6 +126,11 @@ impl LlvmType for Reg { _ => bug!("unsupported float: {:?}", self), }, RegKind::Vector => cx.type_vector(cx.type_i8(), self.size.bytes()), + // Generate a LLVM type such as , like above for a non scalable + // vector. The use of 16 here is chosen as that will generate a valid type with both + // Arm SVE and RISC-V RVV. In the future with other architectures this might not be + // valid and might have to be configured by the target. + RegKind::ScalableVector => cx.type_scalable_vector(cx.type_i8(), 16), } } } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 72ff9ea118e28..2d369594f77dc 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -537,7 +537,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { panic!("unsized locals must not be `extern` types"); } } - assert_eq!(place.val.llextra.is_some(), place.layout.is_unsized()); + + if !place.layout.is_runtime_sized() { + assert_eq!(place.val.llextra.is_some(), place.layout.is_unsized()); + } if place.layout.is_zst() { return OperandRef::zero_sized(place.layout); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 851a4c42e99b4..b5c6bcf771e54 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1091,6 +1091,7 @@ fn build_struct_type_di_node<'ll, 'tcx>( Cow::Borrowed(f.name.as_str()) }; let field_layout = struct_type_and_layout.field(cx, i); + build_field_di_node( cx, owner, diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 68c3d47e826bf..37aff2784f593 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -11,7 +11,7 @@ use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh, wants_wasm_eh} use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; use rustc_codegen_ssa::errors::{ExpectedPointerMutability, InvalidMonomorphization}; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; -use rustc_codegen_ssa::mir::place::PlaceRef; +use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue}; use rustc_codegen_ssa::traits::*; use rustc_hir as hir; use rustc_middle::mir::BinOp; @@ -406,6 +406,14 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { let use_integer_compare = match layout.abi() { Scalar(_) | ScalarPair(_, _) => true, Uninhabited | Vector { .. } => false, + ScalableVector { .. } => { + tcx.dcx().emit_err(InvalidMonomorphization::NonScalableType { + span, + name: sym::raw_eq, + ty: tp_ty, + }); + return Ok(()); + } Aggregate { .. } => { // For rusty ABIs, small aggregates are actually passed // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), @@ -1155,6 +1163,18 @@ fn generic_simd_intrinsic<'ll, 'tcx>( return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate())); } + if name == sym::simd_reinterpret { + require_simd!(ret_ty, SimdReturn); + + return Ok(match args[0].val { + OperandValue::Ref(PlaceValue { llval: val, .. }) | OperandValue::Immediate(val) => { + bx.bitcast(val, llret_ty) + } + OperandValue::ZeroSized => bx.const_undef(llret_ty), + OperandValue::Pair(_, _) => todo!(), + }); + } + // every intrinsic below takes a SIMD vector as its first argument let (in_len, in_elem) = require_simd!(arg_tys[0], SimdInput); let in_ty = arg_tys[0]; @@ -1368,12 +1388,17 @@ fn generic_simd_intrinsic<'ll, 'tcx>( InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len } ); match m_elem_ty.kind() { - ty::Int(_) => {} + // Arm SVE has a svbool type and we need to represent that as a bool in the type system. + ty::Int(_) | ty::Bool => {} _ => return_error!(InvalidMonomorphization::MaskType { span, name, ty: m_elem_ty }), } // truncate the mask to a vector of i1s let i1 = bx.type_i1(); - let i1xn = bx.type_vector(i1, m_len as u64); + let i1xn = if arg_tys[1].is_scalable_simd() { + bx.type_scalable_vector(i1, m_len as u64) + } else { + bx.type_vector(i1, m_len as u64) + }; let m_i1s = bx.trunc(args[0].immediate(), i1xn); return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate())); } @@ -2345,6 +2370,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( out_elem }); } + macro_rules! arith_binary { ($($name: ident: $($($p: ident),* => $call: ident),*;)*) => { $(if name == sym::$name { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index ae46200d3f554..bae5ecfc1334f 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -890,6 +890,7 @@ extern "C" { // Operations on array, pointer, and vector types (sequence types) pub fn LLVMPointerTypeInContext(C: &Context, AddressSpace: c_uint) -> &Type; pub fn LLVMVectorType(ElementType: &Type, ElementCount: c_uint) -> &Type; + pub fn LLVMScalableVectorType(ElementType: &Type, ElementCount: c_uint) -> &Type; pub fn LLVMGetElementType(Ty: &Type) -> &Type; pub fn LLVMGetVectorSize(VectorTy: &Type) -> c_uint; diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index f1141c57cedd7..c12ed1f265eef 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -69,6 +69,10 @@ impl<'ll> CodegenCx<'ll, '_> { unsafe { llvm::LLVMVectorType(ty, len as c_uint) } } + pub(crate) fn type_scalable_vector(&self, ty: &'ll Type, len: u64) -> &'ll Type { + unsafe { llvm::LLVMScalableVectorType(ty, len as c_uint) } + } + pub(crate) fn func_params_types(&self, ty: &'ll Type) -> Vec<&'ll Type> { unsafe { let n_args = llvm::LLVMCountParamTypes(ty) as usize; diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 7be941ed74980..426ea13f0e26c 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -23,6 +23,15 @@ fn uncached_llvm_type<'a, 'tcx>( let element = layout.scalar_llvm_type_at(cx, element); return cx.type_vector(element, count); } + Abi::ScalableVector { ref element, elt } => { + let element = if element.is_bool() { + cx.type_i1() + } else { + layout.scalar_llvm_type_at(cx, *element) + }; + + return cx.type_scalable_vector(element, elt); + } Abi::Uninhabited | Abi::Aggregate { .. } | Abi::ScalarPair(..) => {} } @@ -171,7 +180,7 @@ pub trait LayoutLlvmExt<'tcx> { impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { fn is_llvm_immediate(&self) -> bool { match self.abi { - Abi::Scalar(_) | Abi::Vector { .. } => true, + Abi::Scalar(_) | Abi::Vector { .. } | Abi::ScalableVector { .. } => true, Abi::ScalarPair(..) | Abi::Uninhabited | Abi::Aggregate { .. } => false, } } @@ -179,7 +188,11 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { fn is_llvm_scalar_pair(&self) -> bool { match self.abi { Abi::ScalarPair(..) => true, - Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } | Abi::Aggregate { .. } => false, + Abi::Uninhabited + | Abi::Scalar(_) + | Abi::Vector { .. } + | Abi::ScalableVector { .. } + | Abi::Aggregate { .. } => false, } } diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 000fe2e3ce0f5..478edb154ae1d 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -95,6 +95,7 @@ codegen_ssa_invalid_monomorphization_mask_type = invalid monomorphization of `{$ codegen_ssa_invalid_monomorphization_mismatched_lengths = invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}` +codegen_ssa_invalid_monomorphization_non_scalable_type = invalid monomorphization of `{$name}` intrinsic: expected non-scalable type, found scalable type `{$ty}` codegen_ssa_invalid_monomorphization_return_element = invalid monomorphization of `{$name}` intrinsic: expected return element type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` with element type `{$out_ty}` codegen_ssa_invalid_monomorphization_return_integer_type = invalid monomorphization of `{$name}` intrinsic: expected return type with integer elements, found `{$ret_ty}` with non-integer `{$out_ty}` diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index e9d31db92541b..c77e4dddc1451 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -962,6 +962,14 @@ pub enum InvalidMonomorphization<'tcx> { expected_element: Ty<'tcx>, vector_type: Ty<'tcx>, }, + + #[diag(codegen_ssa_invalid_monomorphization_non_scalable_type, code = E0511)] + NonScalableType { + #[primary_span] + span: Span, + name: Symbol, + ty: Ty<'tcx>, + }, } pub enum ExpectedPointerMutability { diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 6b89636b6540c..2ea6e6b856997 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -351,6 +351,24 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } + // LLVM doesn't handle stores on some of the internal SVE types that we are required + // to use. Spilling to the stack here to create debug info for them will cause + // errors during instruction selection. The types that can't be spilled are an + // internal implementation detail to the intrinsic, the user should never see these + // types, and therefore shouldn't need any debug info for them. + if operand.layout.ty.is_scalable_simd() && bx.sess().target.arch == "aarch64" { + if let ty::Adt(adt, args) = &operand.layout.ty.kind() { + if let Some(f0) = adt.non_enum_variant().fields.get(FieldIdx::from_u32(0)) { + let f0_ty = f0.ty(bx.tcx(), args); + if let ty::Slice(e_ty) = f0_ty.kind() { + if e_ty.is_bool() && adt.repr().scalable != Some(16) { + return; + } + } + } + } + } + Self::spill_operand_to_stack(*operand, name, bx) } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 61f57c9030a1a..7f3d59e54c274 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -248,7 +248,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( if memory_locals.contains(local) { debug!("alloc: {:?} -> place", local); - if layout.is_unsized() { + if layout.is_unsized() && !layout.is_runtime_sized() { LocalRef::UnsizedPlace(PlaceRef::alloca_unsized_indirect(&mut start_bx, layout)) } else { LocalRef::Place(PlaceRef::alloca(&mut start_bx, layout)) diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index cc0e913965067..182acde4a66f8 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -401,7 +401,10 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { bx.store(*llval, llptr, field.align.abi); *llval = bx.load(llfield_ty, llptr, field.align.abi); } - (OperandValue::Immediate(_), Abi::Uninhabited | Abi::Aggregate { sized: false }) => { + ( + OperandValue::Immediate(_), + Abi::Uninhabited | Abi::Aggregate { sized: false } | Abi::ScalableVector { .. }, + ) => { bug!() } (OperandValue::Pair(..), _) => bug!(), diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 97d5bb8312891..d8d165c521f6a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -99,7 +99,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { layout: TyAndLayout<'tcx>, align: Align, ) -> PlaceRef<'tcx, V> { - assert!(layout.is_sized()); + assert!(layout.is_sized() || layout.is_runtime_sized()); PlaceValue::new_sized(llval, align).with_type(layout) } @@ -117,7 +117,10 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { size: Size, layout: TyAndLayout<'tcx>, ) -> Self { - assert!(layout.is_sized(), "tried to statically allocate unsized place"); + assert!( + layout.is_sized() || layout.is_runtime_sized(), + "tried to statically allocate unsized place" + ); PlaceValue::alloca(bx, size, layout.align.abi).with_type(layout) } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index f9e928a84a78e..4e8cb6d4d350e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -1115,6 +1115,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandValueKind::Immediate(match layout.abi { abi::Abi::Scalar(s) => s, abi::Abi::Vector { element, .. } => element, + abi::Abi::ScalableVector { element, .. } => element, x => span_bug!(self.mir.span, "Couldn't translate {x:?} as backend immediate"), }) } else if self.cx.is_backend_scalar_pair(layout) { diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index b1bad6cfa6f58..e254be889e653 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -87,7 +87,7 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> { fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool { let param_env = ty::ParamEnv::reveal_all(); - if ty.is_sized(self.tcx(), param_env) { + if ty.is_sized(self.tcx(), param_env) || ty.is_scalable_simd() { return false; } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 4da7e233889f0..166d034deaf9f 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -993,7 +993,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, self.visit_scalar(b, b_layout)?; } } - Abi::Vector { .. } => { + Abi::Vector { .. } | Abi::ScalableVector { .. } => { // No checks here, we assume layout computation gets this right. // (This is harder to check since Miri does not represent these as `Immediate`. We // also cannot use field projections since this might be a newtype around a vector.) diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index daf57285ebe6d..c634909bcdd5e 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -107,6 +107,7 @@ fn might_permit_raw_init_lax<'tcx>( Abi::Scalar(s) => scalar_allows_raw_init(s), Abi::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2), Abi::Vector { element: s, count } => count == 0 || scalar_allows_raw_init(s), + Abi::ScalableVector { element, .. } => scalar_allows_raw_init(element), Abi::Aggregate { .. } => true, // Fields are checked below. }; if !valid { diff --git a/compiler/rustc_error_codes/src/error_codes/E0799.md b/compiler/rustc_error_codes/src/error_codes/E0799.md new file mode 100644 index 0000000000000..932a6068a397b --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0799.md @@ -0,0 +1,10 @@ +No value of `N` was specified for `repr(scalable(N))` + +Erroneous code example: + +```compile_fail,E0799 +#[repr(scalable)] +struct Foo { + _ty: [i32; 0], +} +``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0800.md b/compiler/rustc_error_codes/src/error_codes/E0800.md new file mode 100644 index 0000000000000..8408336fe7c0b --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0800.md @@ -0,0 +1,9 @@ +A scalable SIMD type was used in a context where they cannot exist. Scalable +SIMD types exist in a place that is somewhere between `Sized` and `Unsized` +therefore have restrictions on the uses. A scalable SIMD type can't exist in any +of the following: + +* Struct +* Enum variant +* Union +* Compound type. diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 2a7bc2501c081..dfa0d9422c1a8 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -537,6 +537,8 @@ E0795: 0795, E0796: 0796, E0797: 0797, E0798: 0798, +E0799: 0799, +E0800: 0800, ); ) } diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 9b5ed3b0876a5..b8604ace3abd4 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -219,6 +219,8 @@ declare_features! ( (internal, prelude_import, "1.2.0", None), /// Used to identify crates that contain the profiler runtime. (internal, profiler_runtime, "1.18.0", None), + /// Allows the use of scalable SIMD types. + (unstable, repr_scalable, "CURRENT_RUSTC_VERSION", None), /// Allows using `rustc_*` attributes (RFC 572). (internal, rustc_attrs, "1.0.0", None), /// Allows using the `#[stable]` and `#[unstable]` attributes. @@ -635,8 +637,22 @@ declare_features! ( /// are not `Sized`, e.g. `fn foo() {`. (incomplete, unsized_const_params, "CURRENT_RUSTC_VERSION", Some(95174)), /// Allows unsized fn parameters. + /// + /// Note: `repr_scalable` depends on this feature. Rather than forcing the developer to also + /// enable this feature to use scalable SIMD, we have done a check along side this feature to + /// check if the type is a scalable SIMD type. If this feature becomes stable, those checks + /// should be safe to remove so we can just use this feature. The check has been done specific + /// to the type rather than enabling this feature on their behalf to avoid enabling more unsized + /// than is actually required for what they are using. (internal, unsized_fn_params, "1.49.0", Some(48055)), /// Allows unsized rvalues at arguments and parameters. + /// + /// Note: `repr_scalable` depends on this feature. Rather than forcing the developer to also + /// enable this feature to use scalable SIMD, we have done a check along side this feature to + /// check if the type is a scalable SIMD type. If this feature becomes stable, those checks + /// should be safe to remove so we can just use this feature. The check has been done specific + /// to the type rather than enabling this feature on their behalf to avoid enabling more unsized + /// than is actually required for what they are using. (incomplete, unsized_locals, "1.30.0", Some(48055)), /// Allows unsized tuple coercion. (unstable, unsized_tuple_coercion, "1.20.0", Some(42877)), diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 27db54181651a..55f6baf0a199e 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -71,7 +71,7 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) { def.destructor(tcx); // force the destructor to be evaluated if def.repr().simd() { - check_simd(tcx, span, def_id); + check_simd(tcx, span, def_id, def.repr().scalable()); } check_transparent(tcx, def); @@ -1054,13 +1054,13 @@ fn check_impl_items_against_trait<'tcx>( } } -pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { +pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId, is_scalable: bool) { let t = tcx.type_of(def_id).instantiate_identity(); if let ty::Adt(def, args) = t.kind() && def.is_struct() { let fields = &def.non_enum_variant().fields; - if fields.is_empty() { + if fields.is_empty() && !is_scalable { struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit(); return; } @@ -1078,7 +1078,7 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { Some(fields.len() as u64) }; if let Some(len) = len { - if len == 0 { + if len == 0 && !is_scalable { struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit(); return; } else if len > MAX_SIMD_LANES { @@ -1107,6 +1107,7 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_, _) ) => { /* struct([f32; 4]) is ok */ } + ty::Slice(_) if is_scalable => (), _ => { struct_span_code_err!( tcx.dcx(), @@ -1739,6 +1740,7 @@ pub(super) fn check_coroutine_obligations( } let errors = ocx.select_all_or_error(); + debug!(?errors); if !errors.is_empty() { return Err(infcx.err_ctxt().report_fulfillment_errors(errors)); diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 6282499883ba4..b302ead8c03b1 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -642,6 +642,7 @@ pub fn check_intrinsic_type( sym::simd_extract => (2, 0, vec![param(0), tcx.types.u32], param(1)), sym::simd_cast | sym::simd_as + | sym::simd_reinterpret | sym::simd_cast_ptr | sym::simd_expose_provenance | sym::simd_with_exposed_provenance => (2, 0, vec![param(0)], param(1)), @@ -672,5 +673,6 @@ pub fn check_intrinsic_type( }; let sig = tcx.mk_fn_sig(inputs, output, false, safety, abi); let sig = ty::Binder::bind_with_vars(sig, bound_vars); + equate_intrinsic_type(tcx, span, intrinsic_id, n_tps, n_lts, n_cts, sig) } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 0316ef69bf83e..d3d5e153b92c6 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1128,10 +1128,9 @@ fn check_type_defn<'tcx>( }; // All fields (except for possibly the last) should be sized. let all_sized = all_sized || variant.fields.is_empty() || needs_drop_copy(); - let unsized_len = if all_sized { 0 } else { 1 }; - for (idx, field) in - variant.fields.raw[..variant.fields.len() - unsized_len].iter().enumerate() - { + let unsized_len = + if all_sized { variant.fields.len() } else { variant.fields.len() - 1 }; + for (idx, field) in variant.fields.raw.iter().enumerate() { let last = idx == variant.fields.len() - 1; let field_id = field.did.expect_local(); let hir::FieldDef { ty: hir_ty, .. } = @@ -1141,28 +1140,45 @@ fn check_type_defn<'tcx>( None, tcx.type_of(field.did).instantiate_identity(), ); - wfcx.register_bound( - traits::ObligationCause::new( + if matches!(ty.kind(), ty::Adt(def, _) if def.repr().scalable()) { + struct_span_code_err!( + tcx.dcx(), hir_ty.span, - wfcx.body_def_id, - ObligationCauseCode::FieldSized { - adt_kind: match &item.kind { - ItemKind::Struct(..) => AdtKind::Struct, - ItemKind::Union(..) => AdtKind::Union, - ItemKind::Enum(..) => AdtKind::Enum, - kind => span_bug!( - item.span, - "should be wfchecking an ADT, got {kind:?}" - ), + E0800, + "Scalable simd types cannot exist within {}", + match &item.kind { + ItemKind::Struct(..) => "a struct", + ItemKind::Union(..) => "a union", + ItemKind::Enum(..) => "enum variants", + kind => + span_bug!(item.span, "should be wfchecking an ADT, got {kind:?}"), + } + ) + .emit(); + } else if idx < unsized_len { + wfcx.register_bound( + traits::ObligationCause::new( + hir_ty.span, + wfcx.body_def_id, + ObligationCauseCode::FieldSized { + adt_kind: match &item.kind { + ItemKind::Struct(..) => AdtKind::Struct, + ItemKind::Union(..) => AdtKind::Union, + ItemKind::Enum(..) => AdtKind::Enum, + kind => span_bug!( + item.span, + "should be wfchecking an ADT, got {kind:?}" + ), + }, + span: hir_ty.span, + last, }, - span: hir_ty.span, - last, - }, - ), - wfcx.param_env, - ty, - tcx.require_lang_item(LangItem::Sized, None), - ); + ), + wfcx.param_env, + ty, + tcx.require_lang_item(LangItem::Sized, None), + ); + } } // Explicit `enum` discriminant values must const-evaluate successfully. diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 843d9e3871489..846fc9f8778b8 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -94,7 +94,7 @@ pub(super) fn check_fn<'a, 'tcx>( } // Check that argument is Sized. - if !params_can_be_unsized { + if !(params_can_be_unsized || param_ty.is_scalable_simd()) { fcx.require_type_is_sized( param_ty, param.pat.span, @@ -120,11 +120,17 @@ pub(super) fn check_fn<'a, 'tcx>( hir::FnRetTy::Return(ty) => ty.span, }; - fcx.require_type_is_sized( - declared_ret_ty, - return_or_body_span, - ObligationCauseCode::SizedReturnType, - ); + // Unsized locals and fn params have a feature gate to allow them. Return types don't + // with scalable vectors we need that feature, for now just remove the check for testing + // purposes. + if !declared_ret_ty.is_scalable_simd() { + fcx.require_type_is_sized( + declared_ret_ty, + return_or_body_span, + ObligationCauseCode::SizedReturnType, + ); + } + // We checked the root's signature during wfcheck, but not the child. if fcx.tcx.is_typeck_child(fn_def_id.to_def_id()) { fcx.require_type_is_sized( @@ -135,6 +141,7 @@ pub(super) fn check_fn<'a, 'tcx>( } fcx.is_whole_body.set(true); + fcx.check_return_expr(body.value, false); // Finalize the return check by taking the LUB of the return types diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 0d002c52fbb86..33990c9547789 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -578,6 +578,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { infer::BoundRegionConversionTime::FnCall, fn_sig.input(i), ); + + if input.is_scalable_simd() { + continue; + } + self.require_type_is_sized_deferred( input, span, @@ -596,11 +601,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { infer::BoundRegionConversionTime::FnCall, fn_sig.output(), ); - self.require_type_is_sized_deferred( - output, - call.map_or(expr.span, |e| e.span), - ObligationCauseCode::SizedCallReturnType, - ); + + if !output.is_scalable_simd() { + // Unsized locals and fn params have a feature gate to allow them. Return types don't + // with scalable vectors we need to be able to return unsized types, for now just + // remove the check for testing purposes. + self.require_type_is_sized_deferred( + output, + call.map_or(expr.span, |e| e.span), + ObligationCauseCode::SizedCallReturnType, + ); + } } // We always require that the type provided as the value for diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 13e4b625e2d0d..e4aad4e406a3e 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -140,7 +140,9 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { let var_ty = self.assign(p.span, p.hir_id, None); if let Some((ty_span, hir_id)) = self.outermost_fn_param_pat { - if !self.fcx.tcx.features().unsized_fn_params { + if !(self.fcx.tcx.features().unsized_fn_params + || self.fcx.tcx.features().repr_scalable) + { self.fcx.require_type_is_sized( var_ty, p.span, @@ -158,7 +160,9 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { ); } } else { - if !self.fcx.tcx.features().unsized_locals { + if !(self.fcx.tcx.features().unsized_locals + || self.fcx.tcx.features().repr_scalable) + { self.fcx.require_type_is_sized( var_ty, p.span, diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 2c79366450909..925b514451921 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -197,7 +197,9 @@ fn typeck_with_fallback<'tcx>( for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) { let ty = fcx.normalize(span, ty); - fcx.require_type_is_sized(ty, span, code); + if !ty.is_scalable_simd() { + fcx.require_type_is_sized(ty, span, code); + } } fcx.select_obligations_where_possible(|_| {}); diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 466397817dae1..607de290ee72a 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -496,7 +496,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let final_upvar_tys = self.final_upvar_tys(closure_def_id); debug!(?closure_hir_id, ?args, ?final_upvar_tys); - if self.tcx.features().unsized_locals || self.tcx.features().unsized_fn_params { + if self.tcx.features().unsized_locals + || self.tcx.features().unsized_fn_params + || self.tcx.features().repr_scalable + { for capture in self.typeck_results.borrow().closure_min_captures_flattened(closure_def_id) { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 558590af7ec19..df1ed46eaa755 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1510,6 +1510,7 @@ impl<'tcx> TyCtxt<'tcx> { let mut size = None; let mut max_align: Option = None; let mut min_pack: Option = None; + let mut elt: Option = None; // Generate a deterministically-derived seed from the item's path hash // to allow for cross-crate compilation to actually work @@ -1538,6 +1539,10 @@ impl<'tcx> TyCtxt<'tcx> { } attr::ReprTransparent => ReprFlags::IS_TRANSPARENT, attr::ReprSimd => ReprFlags::IS_SIMD, + attr::ReprScalable(e) => { + elt = Some(e); + ReprFlags::IS_SCALABLE + } attr::ReprInt(i) => { size = Some(match i { attr::IntType::SignedInt(x) => match x { @@ -1578,7 +1583,14 @@ impl<'tcx> TyCtxt<'tcx> { flags.insert(ReprFlags::IS_LINEAR); } - ReprOptions { int: size, align: max_align, pack: min_pack, flags, field_shuffle_seed } + ReprOptions { + int: size, + align: max_align, + pack: min_pack, + flags, + field_shuffle_seed, + scalable: elt, + } } /// Look up the name of a definition across crates. This does not look at HIR. diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index d2b444a066bcc..8b4e30b4042d7 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1079,6 +1079,14 @@ impl<'tcx> Ty<'tcx> { } } + #[inline] + pub fn is_scalable_simd(self) -> bool { + match self.kind() { + Adt(def, _) => def.repr().simd() && def.repr().scalable(), + _ => false, + } + } + pub fn sequence_element_type(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match self.kind() { Array(ty, _) | Slice(ty) => *ty, @@ -1094,19 +1102,28 @@ impl<'tcx> Ty<'tcx> { let variant = def.non_enum_variant(); let f0_ty = variant.fields[FieldIdx::ZERO].ty(tcx, args); - match f0_ty.kind() { - // If the first field is an array, we assume it is the only field and its - // elements are the SIMD components. - Array(f0_elem_ty, f0_len) => { - // FIXME(repr_simd): https://github.com/rust-lang/rust/pull/78863#discussion_r522784112 - // The way we evaluate the `N` in `[T; N]` here only works since we use - // `simd_size_and_type` post-monomorphization. It will probably start to ICE - // if we use it in generic code. See the `simd-array-trait` ui test. - (f0_len.eval_target_usize(tcx, ParamEnv::empty()), *f0_elem_ty) + if def.repr().scalable() { + match f0_ty.kind() { + Slice(f0_elem_ty) => (def.repr().scalable.unwrap_or(0) as u64, *f0_elem_ty), + _ => { + bug!("Scalable SIMD should be using a slice"); + } + } + } else { + match f0_ty.kind() { + // If the first field is an array, we assume it is the only field and its + // elements are the SIMD components. + Array(f0_elem_ty, f0_len) => { + // FIXME(repr_simd): https://github.com/rust-lang/rust/pull/78863#discussion_r522784112 + // The way we evaluate the `N` in `[T; N]` here only works since we use + // `simd_size_and_type` post-monomorphization. It will probably start to ICE + // if we use it in generic code. See the `simd-array-trait` ui test. + (f0_len.eval_target_usize(tcx, ParamEnv::empty()), *f0_elem_ty) + } + // Otherwise, the fields of this Adt are the SIMD components (and we assume they + // all have the same type). + _ => (variant.fields.len() as u64, f0_ty), } - // Otherwise, the fields of this Adt are the SIMD components (and we assume they - // all have the same type). - _ => (variant.fields.len() as u64, f0_ty), } } _ => bug!("`simd_size_and_type` called on invalid type"), diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs index 09ce134a2bf6c..ad8dd802a6883 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs @@ -166,8 +166,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let ty = expr.ty; let param_env = this.param_env; - if !ty.is_sized(tcx, param_env) { - // !sized means !copy, so this is an unsized move + if !ty.is_sized(tcx, param_env) && !ty.is_scalable_simd() { + // !sized means !copy, so this is an unsized move. assert!(!ty.is_copy_modulo_regions(tcx, param_env)); // As described above, detect the case where we are passing a value of unsized diff --git a/compiler/rustc_mir_build/src/build/misc.rs b/compiler/rustc_mir_build/src/build/misc.rs index 04e6d24e5a172..74cbd017c4687 100644 --- a/compiler/rustc_mir_build/src/build/misc.rs +++ b/compiler/rustc_mir_build/src/build/misc.rs @@ -61,7 +61,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn consume_by_copy_or_move(&self, place: Place<'tcx>) -> Operand<'tcx> { let tcx = self.tcx; let ty = place.ty(&self.local_decls, tcx).ty; - if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty) { + if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty) && !ty.is_scalable_simd() { Operand::Move(place) } else { Operand::Copy(place) diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 658cc4c51a948..7be00541acd03 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1599,7 +1599,11 @@ fn check_field_tys_sized<'tcx>( ) { // No need to check if unsized_locals/unsized_fn_params is disabled, // since we will error during typeck. - if !tcx.features().unsized_locals && !tcx.features().unsized_fn_params { + // repr scalable will also allow unsized locals so if that's enabled we also have to check. + if !tcx.features().unsized_locals + && !tcx.features().unsized_fn_params + && !tcx.features().repr_scalable + { return; } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 3655a677ba0ad..30614d2ecae9c 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1017,7 +1017,7 @@ fn find_vtable_types_for_unsizing<'tcx>( let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| { let param_env = ty::ParamEnv::reveal_all(); let type_has_metadata = |ty: Ty<'tcx>| -> bool { - if ty.is_sized(tcx.tcx, param_env) { + if ty.is_sized(tcx.tcx, param_env) || ty.is_scalable_simd() { return false; } let tail = tcx.struct_tail_erasing_lifetimes(ty, param_env); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 9cbd989cc0e9f..a883f6589442e 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1852,6 +1852,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { continue; } } + sym::scalable => { + continue; + } sym::transparent => { is_transparent = true; match target { diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs index cbc3aae1703ea..c1f065a28c390 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs @@ -214,6 +214,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Abi { ValueAbi::Vector { element: element.stable(tables), count } } rustc_abi::Abi::Aggregate { sized } => ValueAbi::Aggregate { sized }, + rustc_abi::Abi::ScalableVector { element: _element, elt: _elt } => todo!(), } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 2b30ca8a89478..e1e9a0a0ff0ed 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1545,6 +1545,7 @@ symbols! { repr_align, repr_align_enum, repr_packed, + repr_scalable, repr_simd, repr_transparent, require, @@ -1700,6 +1701,7 @@ symbols! { saturating_add, saturating_div, saturating_sub, + scalable, self_in_typedefs, self_struct_ctor, semitransparent, @@ -1769,6 +1771,7 @@ symbols! { simd_reduce_mul_unordered, simd_reduce_or, simd_reduce_xor, + simd_reinterpret, simd_rem, simd_round, simd_saturating_add, diff --git a/compiler/rustc_target/src/abi/call/aarch64.rs b/compiler/rustc_target/src/abi/call/aarch64.rs index 04020d13f22f9..f5926532fb5b9 100644 --- a/compiler/rustc_target/src/abi/call/aarch64.rs +++ b/compiler/rustc_target/src/abi/call/aarch64.rs @@ -29,6 +29,7 @@ where RegKind::Integer => false, RegKind::Float => true, RegKind::Vector => size.bits() == 64 || size.bits() == 128, + RegKind::ScalableVector => true, }; valid_unit.then_some(Uniform::consecutive(unit, size)) diff --git a/compiler/rustc_target/src/abi/call/arm.rs b/compiler/rustc_target/src/abi/call/arm.rs index 9371e1b395865..9298f94cda87f 100644 --- a/compiler/rustc_target/src/abi/call/arm.rs +++ b/compiler/rustc_target/src/abi/call/arm.rs @@ -19,6 +19,7 @@ where RegKind::Integer => false, RegKind::Float => true, RegKind::Vector => size.bits() == 64 || size.bits() == 128, + RegKind::ScalableVector => unreachable!(), }; valid_unit.then_some(Uniform::consecutive(unit, size)) diff --git a/compiler/rustc_target/src/abi/call/loongarch.rs b/compiler/rustc_target/src/abi/call/loongarch.rs index 893818af77c30..bbf76392c1a51 100644 --- a/compiler/rustc_target/src/abi/call/loongarch.rs +++ b/compiler/rustc_target/src/abi/call/loongarch.rs @@ -76,7 +76,10 @@ where } } }, - Abi::Vector { .. } | Abi::Uninhabited => return Err(CannotUseFpConv), + Abi::Vector { .. } | Abi::Uninhabited => { + return Err(CannotUseFpConv); + } + Abi::ScalableVector { .. } => unreachable!(), Abi::ScalarPair(..) | Abi::Aggregate { .. } => match arg_layout.fields { FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 9f13c195e4ce6..5942172c0d167 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -196,6 +196,7 @@ pub enum RegKind { Integer, Float, Vector, + ScalableVector, } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] @@ -242,6 +243,7 @@ impl Reg { _ => panic!("unsupported float: {self:?}"), }, RegKind::Vector => dl.vector_align(self.size).abi, + RegKind::ScalableVector => dl.vector_align(self.size).abi, } } } @@ -425,7 +427,9 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { /// Returns `true` if this is an aggregate type (including a ScalarPair!) fn is_aggregate(&self) -> bool { match self.abi { - Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false, + Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } | Abi::ScalableVector { .. } => { + false + } Abi::ScalarPair(..) | Abi::Aggregate { .. } => true, } } @@ -463,6 +467,9 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { })) } + // Scalable vectors shouldn't exist within a struct. + Abi::ScalableVector { .. } => Err(Heterogeneous), + Abi::ScalarPair(..) | Abi::Aggregate { sized: true } => { // Helper for computing `homogeneous_aggregate`, allowing a custom // starting offset (used below for handling variants). @@ -598,6 +605,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> { ), Abi::Vector { .. } => PassMode::Direct(ArgAttributes::new()), Abi::Aggregate { .. } => Self::indirect_pass_mode(&layout), + Abi::ScalableVector { .. } => PassMode::Direct(ArgAttributes::new()), }; ArgAbi { layout, mode } } diff --git a/compiler/rustc_target/src/abi/call/powerpc64.rs b/compiler/rustc_target/src/abi/call/powerpc64.rs index 11a6cb52babc9..665b1e13b3b22 100644 --- a/compiler/rustc_target/src/abi/call/powerpc64.rs +++ b/compiler/rustc_target/src/abi/call/powerpc64.rs @@ -35,6 +35,7 @@ where RegKind::Integer => false, RegKind::Float => true, RegKind::Vector => arg.layout.size.bits() == 128, + RegKind::ScalableVector => unreachable!(), }; valid_unit.then_some(Uniform::consecutive(unit, arg.layout.size)) diff --git a/compiler/rustc_target/src/abi/call/riscv.rs b/compiler/rustc_target/src/abi/call/riscv.rs index 84f13f8cc5da9..0a27f61d3ab7e 100644 --- a/compiler/rustc_target/src/abi/call/riscv.rs +++ b/compiler/rustc_target/src/abi/call/riscv.rs @@ -82,7 +82,9 @@ where } } }, - Abi::Vector { .. } | Abi::Uninhabited => return Err(CannotUseFpConv), + Abi::Vector { .. } | Abi::ScalableVector { .. } | Abi::Uninhabited => { + return Err(CannotUseFpConv); + } Abi::ScalarPair(..) | Abi::Aggregate { .. } => match arg_layout.fields { FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs index e9aedc3d28a1e..d5e38b1efe1b1 100644 --- a/compiler/rustc_target/src/abi/call/x86.rs +++ b/compiler/rustc_target/src/abi/call/x86.rs @@ -108,6 +108,9 @@ where } false } + Abi::ScalableVector { .. } => { + unreachable!("Scalable Vectors are unsupported on this target") + } } } diff --git a/compiler/rustc_target/src/abi/call/x86_64.rs b/compiler/rustc_target/src/abi/call/x86_64.rs index fcd712489fa40..907284b006f13 100644 --- a/compiler/rustc_target/src/abi/call/x86_64.rs +++ b/compiler/rustc_target/src/abi/call/x86_64.rs @@ -55,7 +55,7 @@ where }, Abi::Vector { .. } => Class::Sse, - + Abi::ScalableVector { .. } => panic!("Scalable vectors not supported"), Abi::ScalarPair(..) | Abi::Aggregate { .. } => { for i in 0..layout.fields.count() { let field_off = off + layout.fields.offset(i); diff --git a/compiler/rustc_target/src/abi/call/x86_win64.rs b/compiler/rustc_target/src/abi/call/x86_win64.rs index 90de1a42bc06b..4cf87eebfb0e7 100644 --- a/compiler/rustc_target/src/abi/call/x86_win64.rs +++ b/compiler/rustc_target/src/abi/call/x86_win64.rs @@ -18,6 +18,7 @@ pub fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { // FIXME(eddyb) there should be a size cap here // (probably what clang calls "illegal vectors"). } + Abi::ScalableVector { .. } => unreachable!(), Abi::Scalar(_) => { if a.layout.size.bytes() > 8 { a.make_indirect(); diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 6045abc50a9da..65afe5cee079a 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -201,6 +201,9 @@ fn layout_of_uncached<'tcx>( } let pointee = tcx.normalize_erasing_regions(param_env, pointee); + if pointee.is_scalable_simd() { + return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr))); + } if pointee.is_sized(tcx, param_env) { return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr))); } @@ -449,6 +452,10 @@ fn layout_of_uncached<'tcx>( }; (*e_ty, *count, true) + } else if let ty::Slice(e_ty) = f0_ty.kind() + && def.repr().scalable() + { + (*e_ty, 1, false) } else { // First ADT field is not an array: (f0_ty, def.non_enum_variant().fields.len() as _, false) @@ -479,7 +486,10 @@ fn layout_of_uncached<'tcx>( .checked_mul(e_len, dl) .ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?; - let (abi, align) = if def.repr().packed() && !e_len.is_power_of_two() { + let (abi, align) = if !def.repr().scalable() + && def.repr().packed() + && !e_len.is_power_of_two() + { // Non-power-of-two vectors have padding up to the next power-of-two. // If we're a packed repr, remove the padding while keeping the alignment as close // to a vector as possible. @@ -490,6 +500,12 @@ fn layout_of_uncached<'tcx>( pref: dl.vector_align(size).pref, }, ) + } else if def.repr().scalable() { + if let Some(elt) = def.repr().scalable { + (Abi::ScalableVector { element: e_abi, elt: elt as u64 }, e_ly.layout.align()) + } else { + bug!("scalable SIMD type `{}` doesn't contain the number of elements", ty,) + } } else { (Abi::Vector { element: e_abi, count: e_len }, dl.vector_align(size)) }; diff --git a/compiler/rustc_ty_utils/src/layout_sanity_check.rs b/compiler/rustc_ty_utils/src/layout_sanity_check.rs index ab7d1be226b3c..9744d95fadb1b 100644 --- a/compiler/rustc_ty_utils/src/layout_sanity_check.rs +++ b/compiler/rustc_ty_utils/src/layout_sanity_check.rs @@ -78,7 +78,7 @@ pub(super) fn sanity_check_layout<'tcx>( let Some((align, size)) = align.zip(size) else { assert_matches!( layout.layout.abi(), - Abi::Uninhabited | Abi::Aggregate { .. }, + Abi::Uninhabited | Abi::Aggregate { .. } | Abi::ScalableVector { .. }, "ABI unexpectedly missing alignment and/or size in {layout:#?}" ); return; @@ -242,7 +242,7 @@ pub(super) fn sanity_check_layout<'tcx>( assert!(align >= element.align(cx).abi); // just sanity-checking `vector_align`. // FIXME: Do some kind of check of the inner type, like for Scalar and ScalarPair. } - Abi::Uninhabited | Abi::Aggregate { .. } => {} // Nothing to check. + Abi::Uninhabited | Abi::Aggregate { .. } | Abi::ScalableVector { .. } => {} // Nothing to check. } } diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index 30734c020b39b..467f2596f7097 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -122,7 +122,7 @@ extern "rust-intrinsic" { /// * Not be infinite /// * Be representable in the return type, after truncating off its fractional part #[rustc_nounwind] - pub fn simd_cast(x: T) -> U; + pub fn simd_cast(x: T) -> U; /// Numerically cast a vector, elementwise. /// @@ -138,6 +138,10 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_as(x: T) -> U; + #[cfg(not(bootstrap))] + #[rustc_nounwind] + pub fn simd_reinterpret(src: Src) -> Dst; + /// Elementwise negation of a vector. /// /// `T` must be a vector of integer or floating-point primitive types. @@ -504,7 +508,7 @@ extern "rust-intrinsic" { /// # Safety /// `mask` must only contain `0` and `!0`. #[rustc_nounwind] - pub fn simd_select(mask: M, if_true: T, if_false: T) -> T; + pub fn simd_select(mask: M, if_true: T, if_false: T) -> T; /// Select elements from a bitmask. /// diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 0ec46412e9522..b3c826ac1145a 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -56,6 +56,7 @@ #![cfg(not(test))] // #![stable(feature = "core", since = "1.6.0")] +#![cfg_attr(not(bootstrap), feature(repr_scalable))] #![doc( html_playground_url = "https://play.rust-lang.org/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", diff --git a/tests/codegen/simd/allow-scalable-references.rs b/tests/codegen/simd/allow-scalable-references.rs new file mode 100644 index 0000000000000..941e51bd6c316 --- /dev/null +++ b/tests/codegen/simd/allow-scalable-references.rs @@ -0,0 +1,51 @@ +//@ only-aarch64 +//@ compile-flags: -C opt-level=2 --edition=2021 + +#![crate_type = "lib"] +#![allow(incomplete_features, internal_features, improper_ctypes)] +#![feature(repr_simd, repr_scalable, simd_ffi, link_llvm_intrinsics)] + +#[repr(simd, scalable(4))] +#[allow(non_camel_case_types)] +pub struct svint32_t { + _ty: [i32], +} + +#[inline(never)] +#[target_feature(enable = "sve")] +pub unsafe fn svdup_n_s32(op: i32) -> svint32_t { + extern "C" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.dup.x.nxv4i32")] + fn _svdup_n_s32(op: i32) -> svint32_t; + } + unsafe { _svdup_n_s32(op) } +} + +#[inline] +#[target_feature(enable = "sve,sve2")] +pub unsafe fn svxar_n_s32(op1: svint32_t, op2: svint32_t) -> svint32_t { + extern "C" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.xar.nxv4i32")] + fn _svxar_n_s32(op1: svint32_t, op2: svint32_t, imm3: i32) -> svint32_t; + } + unsafe { _svxar_n_s32(op1, op2, IMM3) } +} + +#[inline(never)] +#[no_mangle] +#[target_feature(enable = "sve,sve2")] +// CHECK: define @pass_as_ref(ptr noalias nocapture noundef readonly align 4 dereferenceable(4) %a, %b) +pub unsafe fn pass_as_ref(a: &svint32_t, b: svint32_t) -> svint32_t { + // CHECK: load , ptr %a, align 4 + svxar_n_s32::<1>(*a, b) +} + +#[no_mangle] +#[target_feature(enable = "sve,sve2")] +// CHECK: define @test() +pub unsafe fn test() -> svint32_t { + let a = svdup_n_s32(1); + let b = svdup_n_s32(2); + // CHECK: call @pass_as_ref(ptr noalias noundef nonnull readonly align 4 dereferenceable(4) %a, %b) + pass_as_ref(&a, b) +} diff --git a/tests/ui/feature-gates/feature-gate-repr-scalable.rs b/tests/ui/feature-gates/feature-gate-repr-scalable.rs new file mode 100644 index 0000000000000..3419deba60d10 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-repr-scalable.rs @@ -0,0 +1,8 @@ +#![feature(repr_simd)] + +#[repr(simd, scalable(16))] //~ error: Scalable SIMD types are experimental +struct Foo { + _ty: [i8], +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-repr-scalable.stderr b/tests/ui/feature-gates/feature-gate-repr-scalable.stderr new file mode 100644 index 0000000000000..830ba959ba918 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-repr-scalable.stderr @@ -0,0 +1,12 @@ +error[E0658]: Scalable SIMD types are experimental and possibly buggy + --> $DIR/feature-gate-repr-scalable.rs:3:1 + | +LL | #[repr(simd, scalable(16))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(repr_scalable)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/simd/scalable/disallow-array.rs b/tests/ui/simd/scalable/disallow-array.rs new file mode 100644 index 0000000000000..0520d3f58b742 --- /dev/null +++ b/tests/ui/simd/scalable/disallow-array.rs @@ -0,0 +1,10 @@ +#![feature(repr_simd, repr_scalable)] + +#[repr(simd, scalable(4))] +pub struct ScalableSimdFloat { + _ty: [f32] +} + +fn main() { + let x: [ScalableSimdFloat; 2]; //~ ERROR E0277 +} diff --git a/tests/ui/simd/scalable/disallow-array.stderr b/tests/ui/simd/scalable/disallow-array.stderr new file mode 100644 index 0000000000000..e8c92cb51651f --- /dev/null +++ b/tests/ui/simd/scalable/disallow-array.stderr @@ -0,0 +1,17 @@ +error[E0277]: the size for values of type `[f32]` cannot be known at compilation time + --> $DIR/disallow-array.rs:9:12 + | +LL | let x: [ScalableSimdFloat; 2]; + | ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `ScalableSimdFloat`, the trait `Sized` is not implemented for `[f32]`, which is required by `ScalableSimdFloat: Sized` +note: required because it appears within the type `ScalableSimdFloat` + --> $DIR/disallow-array.rs:4:12 + | +LL | pub struct ScalableSimdFloat { + | ^^^^^^^^^^^^^^^^^ + = note: slice and array elements must have `Sized` type + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/simd/scalable/disallow-capture-closure.rs b/tests/ui/simd/scalable/disallow-capture-closure.rs new file mode 100644 index 0000000000000..f3a795437969b --- /dev/null +++ b/tests/ui/simd/scalable/disallow-capture-closure.rs @@ -0,0 +1,51 @@ +//@ only-aarch64 + +#![allow(incomplete_features, internal_features, improper_ctypes)] +#![feature( + repr_simd, + repr_scalable, + simd_ffi, + unsized_locals, + unsized_fn_params, + link_llvm_intrinsics +)] + +#[repr(simd, scalable(4))] +#[allow(non_camel_case_types)] +pub struct svint32_t { + _ty: [i32], +} + +#[inline(never)] +#[target_feature(enable = "sve")] +pub unsafe fn svdup_n_s32(op: i32) -> svint32_t { + extern "C" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.dup.x.nxv4i32")] + fn _svdup_n_s32(op: i32) -> svint32_t; + } + unsafe { _svdup_n_s32(op) } +} + +#[inline] +#[target_feature(enable = "sve,sve2")] +pub unsafe fn svxar_n_s32(op1: svint32_t, op2: svint32_t) -> svint32_t { + extern "C" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.xar.nxv4i32")] + fn _svxar_n_s32(op1: svint32_t, op2: svint32_t, imm3: i32) -> svint32_t; + } + unsafe { _svxar_n_s32(op1, op2, IMM3) } +} + +#[inline(never)] +fn run(f: impl Fn() -> ()) { + f(); +} + +fn main() { + unsafe { + let a = svdup_n_s32(42); + run(move || { + svxar_n_s32::<2>(a, a); //~ ERROR E0277 + }); + } +} diff --git a/tests/ui/simd/scalable/disallow-capture-closure.stderr b/tests/ui/simd/scalable/disallow-capture-closure.stderr new file mode 100644 index 0000000000000..42639843d0171 --- /dev/null +++ b/tests/ui/simd/scalable/disallow-capture-closure.stderr @@ -0,0 +1,19 @@ +error[E0277]: the size for values of type `[i32]` cannot be known at compilation time + --> $DIR/disallow-capture-closure.rs:48:30 + | +LL | run(move || { + | -- this closure captures all values by move +LL | svxar_n_s32::<2>(a, a); + | ^ doesn't have a size known at compile-time + | + = help: within `svint32_t`, the trait `Sized` is not implemented for `[i32]`, which is required by `svint32_t: Sized` +note: required because it appears within the type `svint32_t` + --> $DIR/disallow-capture-closure.rs:15:12 + | +LL | pub struct svint32_t { + | ^^^^^^^^^ + = note: all values captured by value by a closure must have a statically known size + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/simd/scalable/disallow-enum.rs b/tests/ui/simd/scalable/disallow-enum.rs new file mode 100644 index 0000000000000..4372ef924d24f --- /dev/null +++ b/tests/ui/simd/scalable/disallow-enum.rs @@ -0,0 +1,14 @@ +#![feature(repr_simd, repr_scalable)] + +#[repr(simd, scalable(4))] +pub struct ScalableSimdFloat { + _ty: [f32] +} + +pub enum Invalid { + Scalable(ScalableSimdFloat), //~ ERROR E0800 + Int(i32), +} + +fn main() { +} diff --git a/tests/ui/simd/scalable/disallow-enum.stderr b/tests/ui/simd/scalable/disallow-enum.stderr new file mode 100644 index 0000000000000..2d6d48d655015 --- /dev/null +++ b/tests/ui/simd/scalable/disallow-enum.stderr @@ -0,0 +1,9 @@ +error[E0800]: Scalable simd types cannot exist within enum variants + --> $DIR/disallow-enum.rs:9:14 + | +LL | Scalable(ScalableSimdFloat), + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0800`. diff --git a/tests/ui/simd/scalable/disallow-struct.rs b/tests/ui/simd/scalable/disallow-struct.rs new file mode 100644 index 0000000000000..32727d60bd81f --- /dev/null +++ b/tests/ui/simd/scalable/disallow-struct.rs @@ -0,0 +1,17 @@ +#![feature(repr_simd, repr_scalable)] + +#[repr(simd, scalable(4))] +pub struct ScalableSimdFloat { + _ty: [f32] +} + +pub struct Invalid { + x: ScalableSimdFloat, //~ ERROR E0800 + last: i32, +} + +#[repr(transparent)] +struct Wrap(ScalableSimdFloat); //~ ERROR E0800 + +fn main() { +} diff --git a/tests/ui/simd/scalable/disallow-struct.stderr b/tests/ui/simd/scalable/disallow-struct.stderr new file mode 100644 index 0000000000000..abf2954f6df01 --- /dev/null +++ b/tests/ui/simd/scalable/disallow-struct.stderr @@ -0,0 +1,15 @@ +error[E0800]: Scalable simd types cannot exist within a struct + --> $DIR/disallow-struct.rs:9:8 + | +LL | x: ScalableSimdFloat, + | ^^^^^^^^^^^^^^^^^ + +error[E0800]: Scalable simd types cannot exist within a struct + --> $DIR/disallow-struct.rs:14:13 + | +LL | struct Wrap(ScalableSimdFloat); + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0800`. diff --git a/tests/ui/simd/scalable/disallow-union.rs b/tests/ui/simd/scalable/disallow-union.rs new file mode 100644 index 0000000000000..180f613f7051d --- /dev/null +++ b/tests/ui/simd/scalable/disallow-union.rs @@ -0,0 +1,16 @@ +#![feature(repr_simd, repr_scalable)] + +#[repr(simd, scalable(4))] +pub struct ScalableSimdFloat { + _ty: [f32] +} + +pub union Invalid { + x: ScalableSimdFloat, + //~^ ERROR E0740 + //~^^ ERROR E0800 + other: i32, +} + +fn main() { +} diff --git a/tests/ui/simd/scalable/disallow-union.stderr b/tests/ui/simd/scalable/disallow-union.stderr new file mode 100644 index 0000000000000..dc2cf4368acf1 --- /dev/null +++ b/tests/ui/simd/scalable/disallow-union.stderr @@ -0,0 +1,22 @@ +error[E0800]: Scalable simd types cannot exist within a union + --> $DIR/disallow-union.rs:9:8 + | +LL | x: ScalableSimdFloat, + | ^^^^^^^^^^^^^^^^^ + +error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union + --> $DIR/disallow-union.rs:9:5 + | +LL | x: ScalableSimdFloat, + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>` +help: wrap the field type in `ManuallyDrop<...>` + | +LL | x: std::mem::ManuallyDrop, + | +++++++++++++++++++++++ + + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0740, E0800. +For more information about an error, try `rustc --explain E0740`. diff --git a/tests/ui/simd/scalable/no-async.rs b/tests/ui/simd/scalable/no-async.rs new file mode 100644 index 0000000000000..4143d1e544379 --- /dev/null +++ b/tests/ui/simd/scalable/no-async.rs @@ -0,0 +1,45 @@ +//@ only-aarch64 +//@ edition:2021 + +#![allow(incomplete_features, internal_features, improper_ctypes)] +#![feature( + core_intrinsics, + repr_simd, + repr_scalable, + simd_ffi, + link_llvm_intrinsics +)] + +use core::intrinsics::simd::simd_reinterpret; + +#[repr(simd, scalable(4))] +#[allow(non_camel_case_types)] +pub struct svint32_t { + _ty: [i32], +} + +#[target_feature(enable = "sve")] +pub unsafe fn svdup_n_s32(op: i32) -> svint32_t { + extern "C" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.dup.x.nxv4i32")] + fn _svdup_n_s32(op: i32) -> svint32_t; + } + unsafe { _svdup_n_s32(op) } +} + +async fn another() -> i32 { + 42 +} + +#[no_mangle] +pub async fn test_function() { + unsafe { + let x = svdup_n_s32(1); //~ ERROR E0277 + let temp = another().await; + let y: svint32_t = simd_reinterpret(x); + } +} + +fn main() { + let _ = test_function(); +} diff --git a/tests/ui/simd/scalable/no-async.stderr b/tests/ui/simd/scalable/no-async.stderr new file mode 100644 index 0000000000000..5becbb46c8caf --- /dev/null +++ b/tests/ui/simd/scalable/no-async.stderr @@ -0,0 +1,17 @@ +error[E0277]: the size for values of type `[i32]` cannot be known at compilation time + --> $DIR/no-async.rs:37:13 + | +LL | let x = svdup_n_s32(1); + | ^ doesn't have a size known at compile-time + | + = help: within `svint32_t`, the trait `Sized` is not implemented for `[i32]`, which is required by `svint32_t: Sized` +note: required because it appears within the type `svint32_t` + --> $DIR/no-async.rs:17:12 + | +LL | pub struct svint32_t { + | ^^^^^^^^^ + = note: all values live across `await` must have a statically known size + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/simd/scalable/no-fn-trait.rs b/tests/ui/simd/scalable/no-fn-trait.rs new file mode 100644 index 0000000000000..970edaaeaf9d5 --- /dev/null +++ b/tests/ui/simd/scalable/no-fn-trait.rs @@ -0,0 +1,14 @@ +#![feature(repr_simd, repr_scalable)] + +#[repr(simd, scalable(4))] +pub struct ScalableSimdFloat { + _ty: [f32], +} + +unsafe fn test(f: T) +where + T: Fn(ScalableSimdFloat), //~ ERROR E0277 +{ +} + +fn main() {} diff --git a/tests/ui/simd/scalable/no-fn-trait.stderr b/tests/ui/simd/scalable/no-fn-trait.stderr new file mode 100644 index 0000000000000..2de0e8d832128 --- /dev/null +++ b/tests/ui/simd/scalable/no-fn-trait.stderr @@ -0,0 +1,19 @@ +error[E0277]: the size for values of type `[f32]` cannot be known at compilation time + --> $DIR/no-fn-trait.rs:10:8 + | +LL | T: Fn(ScalableSimdFloat), + | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `(ScalableSimdFloat,)`, the trait `Sized` is not implemented for `[f32]`, which is required by `(ScalableSimdFloat,): Sized` +note: required because it appears within the type `ScalableSimdFloat` + --> $DIR/no-fn-trait.rs:4:12 + | +LL | pub struct ScalableSimdFloat { + | ^^^^^^^^^^^^^^^^^ + = note: required because it appears within the type `(ScalableSimdFloat,)` +note: required by an implicit `Sized` bound in `Fn` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout index b2431698cc645..4b0dba66cbab9 100644 --- a/tests/ui/thir-print/thir-tree-match.stdout +++ b/tests/ui/thir-print/thir-tree-match.stdout @@ -94,7 +94,7 @@ body: did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo) variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])) }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] flags: IS_ENUM - repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 3477539199540094892 } + repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 3477539199540094892 } args: [] variant_index: 0 subpatterns: [ @@ -108,7 +108,7 @@ body: did: DefId(0:3 ~ thir_tree_match[fcf8]::Bar) variants: [VariantDef { def_id: DefId(0:4 ~ thir_tree_match[fcf8]::Bar::First), ctor: Some((Const, DefId(0:5 ~ thir_tree_match[fcf8]::Bar::First::{constructor#0}))), name: "First", discr: Relative(0), fields: [], tainted: None, flags: }, VariantDef { def_id: DefId(0:6 ~ thir_tree_match[fcf8]::Bar::Second), ctor: Some((Const, DefId(0:7 ~ thir_tree_match[fcf8]::Bar::Second::{constructor#0}))), name: "Second", discr: Relative(1), fields: [], tainted: None, flags: }, VariantDef { def_id: DefId(0:8 ~ thir_tree_match[fcf8]::Bar::Third), ctor: Some((Const, DefId(0:9 ~ thir_tree_match[fcf8]::Bar::Third::{constructor#0}))), name: "Third", discr: Relative(2), fields: [], tainted: None, flags: }] flags: IS_ENUM - repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 10333377570083945360 } + repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 10333377570083945360 } args: [] variant_index: 0 subpatterns: [] @@ -156,7 +156,7 @@ body: did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo) variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])) }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] flags: IS_ENUM - repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 3477539199540094892 } + repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 3477539199540094892 } args: [] variant_index: 0 subpatterns: [ @@ -208,7 +208,7 @@ body: did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo) variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])) }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] flags: IS_ENUM - repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 3477539199540094892 } + repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 3477539199540094892 } args: [] variant_index: 1 subpatterns: []