diff --git a/compiler/rustc_abi/src/callconv.rs b/compiler/rustc_abi/src/callconv.rs index a21e1aee9b08a..360f5689cee40 100644 --- a/compiler/rustc_abi/src/callconv.rs +++ b/compiler/rustc_abi/src/callconv.rs @@ -82,6 +82,8 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { })) } + BackendRepr::ScalableVector { .. } => Err(Heterogeneous), + BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => { // Helper for computing `homogeneous_aggregate`, allowing a custom // starting offset (used below for handling variants). diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 80b44e432eeb0..0964c13ec6594 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -151,6 +151,7 @@ impl LayoutCalculator { element: F, count: u64, repr_packed: bool, + scalable: Option, ) -> LayoutCalculatorResult { let elt = element.as_ref(); if count == 0 { @@ -169,7 +170,12 @@ impl LayoutCalculator { let dl = self.cx.data_layout(); let size = elt.size.checked_mul(count, dl).ok_or_else(|| LayoutCalculatorError::SizeOverflow)?; - let (repr, align) = if repr_packed && !count.is_power_of_two() { + let (repr, align) = if let Some(elt) = scalable { + ( + BackendRepr::ScalableVector { element: e_repr, count: elt as u64 }, + dl.llvmlike_vector_align(size), + ) + } else if repr_packed && !count.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. @@ -461,6 +467,7 @@ impl LayoutCalculator { BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..) | BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } | BackendRepr::Memory { .. } => repr, }, }; @@ -532,7 +539,8 @@ impl LayoutCalculator { hide_niches(a); hide_niches(b); } - BackendRepr::SimdVector { element, count: _ } => hide_niches(element), + BackendRepr::SimdVector { element, .. } + | BackendRepr::ScalableVector { element, .. } => hide_niches(element), BackendRepr::Memory { sized: _ } => {} } st.largest_niche = None; diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index de4b5a46c81aa..0240a4107755d 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -93,9 +93,11 @@ bitflags! { // Other flags can still inhibit reordering and thus randomization. // 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 FIELD_ORDER_UNOPTIMIZABLE = ReprFlags::IS_C.bits() | ReprFlags::IS_SIMD.bits() + | ReprFlags::IS_SCALABLE.bits() | ReprFlags::IS_LINEAR.bits(); const ABI_UNOPTIMIZABLE = ReprFlags::IS_C.bits() | ReprFlags::IS_SIMD.bits(); } @@ -143,6 +145,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 @@ -159,6 +162,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) @@ -1663,6 +1671,10 @@ impl AddressSpace { pub enum BackendRepr { Scalar(Scalar), ScalarPair(Scalar, Scalar), + ScalableVector { + element: Scalar, + count: u64, + }, SimdVector { element: Scalar, count: u64, @@ -1681,6 +1693,9 @@ impl BackendRepr { match *self { BackendRepr::Scalar(_) | BackendRepr::ScalarPair(..) + // FIXME(repr_scalable): Scalable vectors are forced to be `Sized` while the + // `sized_hierarchy` feature is not yet fully implemented + | BackendRepr::ScalableVector { .. } | BackendRepr::SimdVector { .. } => false, BackendRepr::Memory { sized } => !sized, } @@ -1721,7 +1736,9 @@ impl BackendRepr { BackendRepr::Scalar(s) => Some(s.align(cx).abi), BackendRepr::ScalarPair(s1, s2) => Some(s1.align(cx).max(s2.align(cx)).abi), // The align of a Vector can vary in surprising ways - BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => None, + BackendRepr::SimdVector { .. } + | BackendRepr::Memory { .. } + | BackendRepr::ScalableVector { .. } => None, } } @@ -1743,7 +1760,9 @@ impl BackendRepr { Some(size) } // The size of a Vector can vary in surprising ways - BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => None, + BackendRepr::SimdVector { .. } + | BackendRepr::Memory { .. } + | BackendRepr::ScalableVector { .. } => None, } } @@ -1758,6 +1777,9 @@ impl BackendRepr { BackendRepr::SimdVector { element: element.to_union(), count } } BackendRepr::Memory { .. } => BackendRepr::Memory { sized: true }, + BackendRepr::ScalableVector { element, count } => { + BackendRepr::ScalableVector { element: element.to_union(), count } + } } } @@ -1998,7 +2020,9 @@ impl LayoutData { /// Returns `true` if this is an aggregate type (including a ScalarPair!) pub fn is_aggregate(&self) -> bool { match self.backend_repr { - BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => false, + BackendRepr::Scalar(_) + | BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } => false, BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => true, } } @@ -2092,6 +2116,19 @@ impl LayoutData { 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.backend_repr, BackendRepr::ScalableVector { .. }) + } + + /// Returns the elements count of a scalable vector. + pub fn scalable_vector_element_count(&self) -> Option { + match self.backend_repr { + BackendRepr::ScalableVector { count, .. } => Some(count), + _ => None, + } + } + /// 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 @@ -2100,6 +2137,7 @@ impl LayoutData { match self.backend_repr { BackendRepr::Scalar(_) | BackendRepr::ScalarPair(..) + | BackendRepr::ScalableVector { .. } | BackendRepr::SimdVector { .. } => false, BackendRepr::Memory { sized } => sized && self.size.bytes() == 0, } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 8114733f40670..7cf1b5fa20cf5 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -213,6 +213,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 vector types are experimental" + ); + } } } } diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 41a9e8feaafab..b7524c3c27eef 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -65,6 +65,7 @@ pub enum ReprAttr { ReprC, ReprPacked(Align), ReprSimd, + ReprScalable(ScalableElt), ReprTransparent, ReprAlign(Align), } @@ -82,6 +83,13 @@ pub enum IntType { UnsignedInt(ast::UintTy), } +/// The base multiple of lanes that are in a scalable vector. +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Encodable, Decodable, HashStable_Generic, PrintAttribute)] +pub struct ScalableElt { + pub elt: u16, +} + #[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)] pub struct Deprecation { pub since: DeprecatedSince, diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index bec3a1e8a599b..8fd05029e71b9 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -114,6 +114,10 @@ attr_parsing_rustc_allowed_unstable_pairing = attr_parsing_rustc_promotable_pairing = `rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute +attr_parsing_scalable_missing_n = + invalid `scalable(num)` attribute: `scalable` needs an argument + .suggestion = supply an argument here + attr_parsing_soft_no_args = `soft` should not have any arguments diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 6a45832ed7fda..cd81c9e04e5d7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -1,6 +1,6 @@ use rustc_abi::Align; use rustc_ast::{IntTy, LitIntType, LitKind, UintTy}; -use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr}; +use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr, ScalableElt}; use rustc_feature::{AttributeTemplate, template}; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; @@ -144,6 +144,11 @@ fn parse_repr( (Some(sym::Rust), ArgParser::NoArgs) => Some(ReprRust), (Some(sym::C), ArgParser::NoArgs) => Some(ReprC), (Some(sym::simd), ArgParser::NoArgs) => Some(ReprSimd), + (Some(sym::scalable), ArgParser::List(l)) => parse_repr_scalable(cx, l, param.span()), + (Some(sym::scalable), ArgParser::NoArgs) => { + cx.emit_err(session_diagnostics::ScalableAttrMissingN { span: param.span() }); + None + } (Some(sym::transparent), ArgParser::NoArgs) => Some(ReprTransparent), (Some(name @ int_pat!()), ArgParser::NoArgs) => { // int_pat!() should make sure it always parses @@ -322,3 +327,18 @@ impl AttributeParser for AlignParser { Some(AttributeKind::Align { align, span }) } } + +fn parse_repr_scalable( + cx: &AcceptContext<'_, '_, S>, + list: &MetaItemListParser<'_>, + span: Span, +) -> Option { + let Some(LitKind::Int(literal, LitIntType::Unsuffixed)) = + list.single().and_then(|elt| elt.lit()).map(|lit| lit.kind) + else { + cx.emit_err(session_diagnostics::ScalableAttrMissingN { span }); + return None; + }; + + literal.get().try_into().ok().map(|elt| ReprAttr::ReprScalable(ScalableElt { elt })) +} diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 28f6786f37fae..255c318fbc71b 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -635,3 +635,11 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { diag } } + +#[derive(Diagnostic)] +#[diag(attr_parsing_scalable_missing_n)] +pub(crate) struct ScalableAttrMissingN { + #[primary_span] + #[suggestion(applicability = "has-placeholders", code = "scalable(...)")] + pub span: Span, +} diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index 69f8c273797e4..83a3ee3c3009f 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -33,37 +33,48 @@ pub(crate) fn expand_deriving_clone( let substructure; let is_simple; match item { - Annotatable::Item(annitem) => match &annitem.kind { - ItemKind::Struct(_, Generics { params, .. }, _) - | ItemKind::Enum(_, Generics { params, .. }, _) => { - let container_id = cx.current_expansion.id.expn_data().parent.expect_local(); - let has_derive_copy = cx.resolver.has_derive_copy(container_id); - if has_derive_copy - && !params - .iter() - .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) - { - bounds = vec![]; + Annotatable::Item(annitem) => { + let has_repr_scalable = annitem.attrs.iter().any(|attr| { + attr.has_name(sym::repr) + && attr + .meta_item_list() + .map(|list| list.iter().any(|inner| inner.has_name(sym::scalable))) + .unwrap_or(false) + }); + + match &annitem.kind { + ItemKind::Struct(_, Generics { params, .. }, _) + | ItemKind::Enum(_, Generics { params, .. }, _) => { + let container_id = cx.current_expansion.id.expn_data().parent.expect_local(); + let has_derive_copy = cx.resolver.has_derive_copy(container_id); + if has_derive_copy + && !params + .iter() + .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) + { + bounds = vec![]; + is_simple = true; + substructure = combine_substructure(Box::new(move |c, s, sub| { + cs_clone_simple("Clone", c, s, sub, false, has_repr_scalable) + })); + } else { + bounds = vec![]; + is_simple = false; + substructure = combine_substructure(Box::new(|c, s, sub| { + cs_clone("Clone", c, s, sub) + })); + } + } + ItemKind::Union(..) => { + bounds = vec![Path(path_std!(marker::Copy))]; is_simple = true; - substructure = combine_substructure(Box::new(|c, s, sub| { - cs_clone_simple("Clone", c, s, sub, false) + substructure = combine_substructure(Box::new(move |c, s, sub| { + cs_clone_simple("Clone", c, s, sub, true, has_repr_scalable) })); - } else { - bounds = vec![]; - is_simple = false; - substructure = - combine_substructure(Box::new(|c, s, sub| cs_clone("Clone", c, s, sub))); } + _ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on wrong item kind"), } - ItemKind::Union(..) => { - bounds = vec![Path(path_std!(marker::Copy))]; - is_simple = true; - substructure = combine_substructure(Box::new(|c, s, sub| { - cs_clone_simple("Clone", c, s, sub, true) - })); - } - _ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on wrong item kind"), - }, + } _ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on trait item or impl item"), } @@ -98,6 +109,7 @@ fn cs_clone_simple( trait_span: Span, substr: &Substructure<'_>, is_union: bool, + has_repr_scalable: bool, ) -> BlockOrExpr { let mut stmts = ThinVec::new(); let mut seen_type_names = FxHashSet::default(); @@ -112,6 +124,9 @@ fn cs_clone_simple( // Already produced an assertion for this type. // Anonymous structs or unions must be eliminated as they cannot be // type parameters. + } else if has_repr_scalable { + // Fields of scalable vector types are just markers for codegen, don't assert they + // implement `Clone` } else { // let _: AssertParamIsClone; super::assert_ty_bounds( diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 28d1ec7d89564..322be5ba08335 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -926,6 +926,10 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { .get_address(self.location) } + fn scalable_alloca(&mut self, _elt: u64, _align: Align, _element_ty: Ty<'_>) -> RValue<'gcc> { + todo!() + } + fn load(&mut self, pointee_ty: Type<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> { let block = self.llbb(); let function = block.get_function(); diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 0753ac1aeb84e..d09b9e53a32c7 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -536,7 +536,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc let layout = self.layout_of(tp_ty).layout; let _use_integer_compare = match layout.backend_repr() { Scalar(_) | ScalarPair(_, _) => true, - SimdVector { .. } => false, + SimdVector { .. } | ScalableVector { .. } => false, Memory { .. } => { // 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 093f902bc3d86..aeb0b7c08cedd 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -85,6 +85,7 @@ fn uncached_gcc_type<'gcc, 'tcx>( ); } BackendRepr::Memory { .. } => {} + BackendRepr::ScalableVector { .. } => todo!(), } let name = match *layout.ty.kind() { @@ -178,7 +179,9 @@ pub trait LayoutGccExt<'tcx> { impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { fn is_gcc_immediate(&self) -> bool { match self.backend_repr { - BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => true, + BackendRepr::Scalar(_) + | BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } => true, BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => false, } } @@ -188,6 +191,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { BackendRepr::ScalarPair(..) => true, BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } | BackendRepr::Memory { .. } => false, } } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 9c3b866aa3c6f..92655e17328c0 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -538,6 +538,25 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } } + fn scalable_alloca(&mut self, elt: u64, align: Align, element_ty: Ty<'_>) -> Self::Value { + let mut bx = Builder::with_cx(self.cx); + bx.position_at_start(unsafe { llvm::LLVMGetFirstBasicBlock(self.llfn()) }); + let llvm_ty = match element_ty.kind() { + ty::Bool => bx.type_i1(), + ty::Int(int_ty) => self.cx.type_int_from_ty(*int_ty), + ty::Uint(uint_ty) => self.cx.type_uint_from_ty(*uint_ty), + ty::Float(float_ty) => self.cx.type_float_from_ty(*float_ty), + _ => unreachable!("scalable vectors can only contain a bool, int, uint or float"), + }; + + unsafe { + let ty = llvm::LLVMScalableVectorType(llvm_ty, elt.try_into().unwrap()); + let alloca = llvm::LLVMBuildAlloca(&bx.llbuilder, ty, UNNAMED); + llvm::LLVMSetAlignment(alloca, align.bytes() as c_uint); + alloca + } + } + fn load(&mut self, ty: &'ll Type, ptr: &'ll Value, align: Align) -> &'ll Value { unsafe { let load = llvm::LLVMBuildLoad2(self.llbuilder, ty, ptr, UNNAMED); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index fcc0d378f0686..8c83b1690fc39 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -454,6 +454,14 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { let use_integer_compare = match layout.backend_repr() { Scalar(_) | ScalarPair(_, _) => true, SimdVector { .. } => false, + ScalableVector { .. } => { + tcx.dcx().emit_err(InvalidMonomorphization::NonScalableType { + span, + name: sym::raw_eq, + ty: tp_ty, + }); + return Ok(()); + } Memory { .. } => { // For rusty ABIs, small aggregates are actually passed // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), @@ -1246,6 +1254,20 @@ 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(_, _) => { + return_error!(InvalidMonomorphization::NonScalableType { span, name, ty: ret_ty }) + } + }); + } + // every intrinsic below takes a SIMD vector as its first argument let (in_len, in_elem) = require_simd!(args[0].layout.ty, SimdInput); let in_ty = args[0].layout.ty; @@ -1441,11 +1463,27 @@ fn generic_simd_intrinsic<'ll, 'tcx>( m_len == v_len, InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len } ); - let in_elem_bitwidth = require_int_or_uint_ty!( - m_elem_ty.kind(), - InvalidMonomorphization::MaskWrongElementType { span, name, ty: m_elem_ty } - ); - let m_i1s = vector_mask_to_bitmask(bx, args[0].immediate(), in_elem_bitwidth, m_len); + + let m_i1s = if args[1].layout.ty.is_scalable_simd() { + match m_elem_ty.kind() { + ty::Bool => {} + _ => return_error!(InvalidMonomorphization::MaskWrongElementType { + span, + name, + ty: m_elem_ty + }), + }; + let i1 = bx.type_i1(); + let i1xn = bx.type_scalable_vector(i1, m_len as u64); + bx.trunc(args[0].immediate(), i1xn) + } else { + let in_elem_bitwidth = require_int_or_uint_ty!( + m_elem_ty.kind(), + InvalidMonomorphization::MaskWrongElementType { span, name, ty: m_elem_ty } + ); + vector_mask_to_bitmask(bx, args[0].immediate(), in_elem_bitwidth, m_len) + }; + return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate())); } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 5c34ab2e3040d..8843b6fac9e4b 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1072,6 +1072,7 @@ unsafe extern "C" { // Operations on array, pointer, and vector types (sequence types) pub(crate) fn LLVMPointerTypeInContext(C: &Context, AddressSpace: c_uint) -> &Type; pub(crate) fn LLVMVectorType(ElementType: &Type, ElementCount: c_uint) -> &Type; + pub(crate) fn LLVMScalableVectorType(ElementType: &Type, ElementCount: c_uint) -> &Type; pub(crate) fn LLVMGetElementType(Ty: &Type) -> &Type; pub(crate) 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 ee472e75ed41e..c91c6a8d7fcdf 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -68,6 +68,10 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { unsafe { llvm::LLVMVectorType(ty, len as c_uint) } } + pub(crate) fn type_scalable_vector(&self, ty: &'ll Type, count: u64) -> &'ll Type { + unsafe { llvm::LLVMScalableVectorType(ty, count 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 4e7096da502d0..1ae926ed9ee1b 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); } + BackendRepr::ScalableVector { ref element, count } => { + let element = if element.is_bool() { + cx.type_i1() + } else { + layout.scalar_llvm_type_at(cx, *element) + }; + + return cx.type_scalable_vector(element, count); + } BackendRepr::Memory { .. } | BackendRepr::ScalarPair(..) => {} } @@ -171,7 +180,9 @@ pub(crate) trait LayoutLlvmExt<'tcx> { impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { fn is_llvm_immediate(&self) -> bool { match self.backend_repr { - BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => true, + BackendRepr::Scalar(_) + | BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } => true, BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => false, } } @@ -181,6 +192,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { BackendRepr::ScalarPair(..) => true, BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } | BackendRepr::Memory { .. } => false, } } diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index ce079f3cb0af1..74787d20dfcef 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -546,7 +546,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>( registers_for_primitive(scalar1.primitive()); registers_for_primitive(scalar2.primitive()); } - BackendRepr::SimdVector { .. } => { + BackendRepr::SimdVector { .. } | BackendRepr::ScalableVector { .. } => { // Because no instance of VaArgSafe uses a non-scalar `BackendRepr`. unreachable!( "No x86-64 SysV va_arg implementation for {:?}", @@ -686,7 +686,9 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>( } } // The Previous match on `BackendRepr` means control flow already escaped. - BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => unreachable!(), + BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } + | BackendRepr::Memory { .. } => unreachable!(), }; // AMD64-ABI 3.5.7p5: Step 5. Set: diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 63e9005da45c2..133883b81e33b 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -131,6 +131,7 @@ codegen_ssa_invalid_monomorphization_mask_wrong_element_type = invalid monomorph 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 e042fe1f81966..645f2c70f4f62 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1084,6 +1084,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 025f5fb54f428..84e636ed47a34 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -361,6 +361,49 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } + // Don't spill `` for `N != 16`: + // + // SVE predicates are only one bit for each byte in an SVE vector (which makes + // sense, the predicate only needs to keep track of whether a lane is + // enabled/disabled). i.e. a `` vector has a `` + // predicate type. `` corresponds to two bytes of storage, + // multiplied by the `vscale`, with one bit for each of the sixteen lanes. + // + // For a vector with fewer elements, such as `svint32_t`/``, + // while only a `` predicate type would be strictly necessary, + // relevant intrinsics still take a `svbool_t`/`` - this is + // because a `` is only half of a byte (for `vscale=1`), and with + // memory being byte-addressable, it's unclear how to store that. + // + // Due to this, LLVM ultimately decided not to support stores of `` + // for `N != 16`. As for `vscale=1` and `N` fewer than sixteen, partial bytes would + // need to be stored (except for `N=8`, but that also isn't supported). `N` can + // never be greater than sixteen as that ends up larger than the 128-bit increment + // size. + // + // Internally, with an intrinsic operating on a `svint32_t`/`` + // (for example), the intrinsic takes the `svbool_t`/`` predicate + // and casts it to a `svbool4_t`/``. Therefore, it's important that + // the `` never spills because that'll cause errors during + // instruction selection. Spilling to the stack to create debuginfo for these + // intermediate values must be avoided and won't degrade the debugging experience + // anyway. + if operand.layout.ty.is_scalable_simd() + && bx.sess().target.arch == "aarch64" + && let ty::Adt(adt, args) = &operand.layout.ty.kind() + && let Some(marker_type_field) = + adt.non_enum_variant().fields.get(FieldIdx::from_u32(0)) + { + let marker_type = marker_type_field.ty(bx.tcx(), args); + // i.e. `` when `N != 16` + if let ty::Slice(element_ty) = marker_type.kind() + && element_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/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index b0d191528a891..dc002c93aca49 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -396,7 +396,9 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { imm } } - BackendRepr::ScalarPair(_, _) | BackendRepr::Memory { .. } => bug!(), + BackendRepr::ScalarPair(_, _) + | BackendRepr::Memory { .. } + | BackendRepr::ScalableVector { .. } => bug!(), }) }; @@ -601,7 +603,9 @@ impl<'a, 'tcx, V: CodegenObject> OperandRefBuilder<'tcx, V> { BackendRepr::ScalarPair(a, b) => { OperandValueBuilder::Pair(Either::Right(a), Either::Right(b)) } - BackendRepr::SimdVector { .. } => OperandValueBuilder::Vector(Either::Right(())), + BackendRepr::SimdVector { .. } | BackendRepr::ScalableVector { .. } => { + OperandValueBuilder::Vector(Either::Right(())) + } BackendRepr::Memory { .. } => { bug!("Cannot use non-ZST Memory-ABI type in operand builder: {layout:?}"); } diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 0090be9fdef06..a6c6e99d337d5 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -109,7 +109,11 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { bx: &mut Bx, layout: TyAndLayout<'tcx>, ) -> Self { - Self::alloca_size(bx, layout.size, layout) + if layout.is_runtime_sized() { + Self::alloca_runtime_sized(bx, layout) + } else { + Self::alloca_size(bx, layout.size, layout) + } } pub fn alloca_size>( @@ -146,6 +150,15 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { bug!("unexpected layout `{:#?}` in PlaceRef::len", self.layout) } } + + fn alloca_runtime_sized>( + bx: &mut Bx, + layout: TyAndLayout<'tcx>, + ) -> Self { + let (elt, ty) = layout.ty.simd_size_and_type(bx.tcx()); + PlaceValue::new_sized(bx.scalable_alloca(elt, layout.align.abi, ty), layout.align.abi) + .with_type(layout) + } } impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index e90463aacc8a1..5182c182fdd57 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -978,6 +978,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // cases like from vectors of f32 to vectors of pointers or // from fat pointers to vectors of u16. (See #143194 #110021 ...) (abi::BackendRepr::SimdVector { .. }, _) | (_, abi::BackendRepr::SimdVector { .. }) => false, + (abi::BackendRepr::ScalableVector { .. }, _) | (_, abi::BackendRepr::ScalableVector { .. }) => false, } } mir::Rvalue::Ref(..) | diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 979456a6ba70f..72d956f80e699 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -234,6 +234,7 @@ pub trait BuilderMethods<'a, 'tcx>: fn to_immediate_scalar(&mut self, val: Self::Value, scalar: Scalar) -> Self::Value; fn alloca(&mut self, size: Size, align: Align) -> Self::Value; + fn scalable_alloca(&mut self, elt: u64, align: Align, element_ty: Ty<'_>) -> Self::Value; fn load(&mut self, ty: Self::Type, ptr: Self::Value, align: Align) -> Self::Value; fn volatile_load(&mut self, ty: Self::Type, ptr: Self::Value) -> Self::Value; diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index fc44490c96d37..19a99830c9b0e 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -1310,7 +1310,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, self.visit_scalar(b, b_layout)?; } } - BackendRepr::SimdVector { .. } => { + BackendRepr::SimdVector { .. } | BackendRepr::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 4ca39bbc68ec2..b07480e27cc1a 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -119,7 +119,9 @@ fn check_validity_requirement_lax<'tcx>( } BackendRepr::SimdVector { element: s, count } => count == 0 || scalar_allows_raw_init(s), BackendRepr::Memory { .. } => true, // Fields are checked below. + BackendRepr::ScalableVector { element, .. } => scalar_allows_raw_init(element), }; + if !valid { // This is definitely not okay. return Ok(false); diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index efd8bde71d76d..c3f30b7f7cc38 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -235,6 +235,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 `repr(scalable)`. + (unstable, repr_scalable, "CURRENT_RUSTC_VERSION", None), /// Allows using `rustc_*` attributes (RFC 572). (internal, rustc_attrs, "1.0.0", None), /// Introduces a hierarchy of `Sized` traits (RFC 3729). diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 70fbb8a543e2a..6782e11b54433 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -95,7 +95,11 @@ 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); + if def.repr().scalable() { + check_scalable_simd(tcx, span, def_id); + } else { + check_simd(tcx, span, def_id); + } } check_transparent(tcx, def); @@ -1393,6 +1397,54 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { } } +fn check_scalable_simd(tcx: TyCtxt<'_>, span: Span, def_id: LocalDefId) { + let ty = tcx.type_of(def_id).instantiate_identity(); + let ty::Adt(def, args) = ty.kind() else { return }; + if !def.is_struct() { + tcx.dcx().delayed_bug("`repr(scalable)` applied to non-struct"); + return; + } + + let fields = &def.non_enum_variant().fields; + match fields.len() { + 0 => { + let mut err = + tcx.dcx().struct_span_err(span, "scalable vectors must have a single field"); + err.help("scalable vector types' only field must be slice of a primitive scalar type"); + err.emit(); + return; + } + 1 => {} + 2.. => { + tcx.dcx().struct_span_err(span, "scalable vectors cannot have multiple fields").emit(); + } + } + + let array_field = &fields[FieldIdx::ZERO]; + let array_ty = array_field.ty(tcx, args); + let ty::Slice(element_ty) = array_ty.kind() else { + let mut err = + tcx.dcx().struct_span_err(span, "the field of a scalable vector type must be a slice"); + err.span_label(tcx.def_span(array_field.did), "not a slice"); + err.emit(); + return; + }; + + // Check that `element_ty` only uses types valid in the lanes of a scalable vector register: + // scalar types which directly match a "machine" type - e.g. integers, floats, bools, thin ptrs. + match element_ty.kind() { + ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_, _) | ty::Bool => (), + _ => { + let mut err = tcx.dcx().struct_span_err( + span, + "element type of a scalable vector must be a primitive scalar", + ); + err.help("only `u*`, `i*`, `f*`, `*const`, `*mut` and `bool` types are accepted"); + err.emit(); + } + } +} + pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { let repr = def.repr(); if repr.packed() { diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index dcab6ef1c5a5f..589d678327a58 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -618,6 +618,7 @@ pub(crate) fn check_intrinsic_type( } 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)), diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 607028f4d9aef..d67d5a9273c8c 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1054,10 +1054,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, .. } = @@ -1067,28 +1066,41 @@ 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()) { + tcx.dcx().span_err( 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:?}" - ), + format!( + "scalable vectors cannot be fields of a {}", + adt_def.variant_descr() + ), + ); + } + + 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, hir_ty.span), - ); + ), + wfcx.param_env, + ty, + tcx.require_lang_item(LangItem::Sized, hir_ty.span), + ); + } } // Explicit `enum` discriminant values must const-evaluate successfully. diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index fc9d795cb2315..a4640ccb23e48 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1191,6 +1191,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { }; } } + // Scalable vectors are passed to C in their vector registers. + if def.repr().scalable() { + return FfiSafe; + } if def.is_phantom_data() { return FfiPhantom(ty); } diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 275458fc85f8d..f6dadb3d0e591 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -208,6 +208,10 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef> for AdtDef<'tcx> { self.is_struct() } + fn is_scalable_vector(self) -> bool { + self.repr().scalable() + } + fn struct_tail_ty(self, interner: TyCtxt<'tcx>) -> Option>> { Some(interner.type_of(self.non_enum_variant().tail_opt()?.did)) } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a352ab3fd08a1..05c6343f4428d 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1513,6 +1513,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 @@ -1542,6 +1543,10 @@ impl<'tcx> TyCtxt<'tcx> { } attr::ReprTransparent => ReprFlags::IS_TRANSPARENT, attr::ReprSimd => ReprFlags::IS_SIMD, + attr::ReprScalable(e) => { + elt = Some(e.elt as u32); + ReprFlags::IS_SCALABLE + } attr::ReprInt(i) => { size = Some(match i { attr::IntType::SignedInt(x) => match x { @@ -1586,7 +1591,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 8bb3b3f1263fa..bb9a0d7db986a 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1194,6 +1194,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, @@ -1210,19 +1218,25 @@ impl<'tcx> Ty<'tcx> { let variant = def.non_enum_variant(); assert_eq!(variant.fields.len(), 1); let field_ty = variant.fields[FieldIdx::ZERO].ty(tcx, args); - let Array(f0_elem_ty, f0_len) = field_ty.kind() else { - bug!("Simd type has non-array field type {field_ty:?}") - }; - // 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 - .try_to_target_usize(tcx) - .expect("expected SIMD field to have definite array size"), - *f0_elem_ty, - ) + + match field_ty.kind() { + 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 + .try_to_target_usize(tcx) + .expect("expected SIMD field to have definite array size"), + *f0_elem_ty, + ) + } + Slice(f0_elem_ty) if def.repr().scalable() => { + (def.repr().scalable.unwrap_or(0) as u64, *f0_elem_ty) + } + _ => bug!("Simd type has non-array field type {field_ty:?}"), + } } #[inline] @@ -1826,9 +1840,12 @@ impl<'tcx> Ty<'tcx> { ty::Tuple(tys) => tys.last().is_none_or(|ty| ty.has_trivial_sizedness(tcx, sizedness)), - ty::Adt(def, args) => def - .sizedness_constraint(tcx, sizedness) - .is_none_or(|ty| ty.instantiate(tcx, args).has_trivial_sizedness(tcx, sizedness)), + ty::Adt(def, args) => { + def.repr().scalable() // see comment on `sizedness_conditions` + || def.sizedness_constraint(tcx, sizedness).is_none_or(|ty| { + ty.instantiate(tcx, args).has_trivial_sizedness(tcx, sizedness) + }) + } ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) | ty::Bound(..) => false, diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 761d5461a996f..25d697e23b58b 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1856,6 +1856,11 @@ fn check_must_not_suspend_ty<'tcx>( SuspendCheckData { descr_pre: &format!("{}allocator ", data.descr_pre), ..data }, ) } + ty::Adt(def, _) if def.repr().scalable() => { + tcx.dcx() + .span_err(data.source_span, "scalable vectors cannot be held over await points"); + true + } ty::Adt(def, _) => check_must_not_suspend_def(tcx, def.did(), hir_id, data), // FIXME: support adding the attribute to TAITs ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => { diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 6b11706d2b55f..7ab6f22b7fb44 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1558,7 +1558,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { BackendRepr::ScalarPair(a, b) => { !a.is_always_valid(&self.ecx) || !b.is_always_valid(&self.ecx) } - BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => false, + BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } + | BackendRepr::Memory { .. } => false, } } diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl index 2bd19e81b01c2..6591ac3cd758c 100644 --- a/compiler/rustc_monomorphize/messages.ftl +++ b/compiler/rustc_monomorphize/messages.ftl @@ -2,7 +2,10 @@ monomorphize_abi_error_disabled_vector_type = this function {$is_call -> [true] call *[false] definition - } uses SIMD vector type `{$ty}` which (with the chosen ABI) requires the `{$required_feature}` target feature, which is not enabled{$is_call -> + } uses {$is_scalable -> + [true] scalable + *[false] SIMD + } vector type `{$ty}` which (with the chosen ABI) requires the `{$required_feature}` target feature, which is not enabled{$is_call -> [true] {" "}in the caller *[false] {""} } diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index 938c427b56c8f..2bf40ebf03bf4 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -75,6 +75,8 @@ pub(crate) struct AbiErrorDisabledVectorType<'a> { pub ty: Ty<'a>, /// Whether this is a problem at a call site or at a declaration. pub is_call: bool, + /// Whether this is a problem with a fixed length vector or a scalable vector + pub is_scalable: bool, } #[derive(Diagnostic)] diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs index b8c001d357e6c..a63296f36fd40 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs @@ -10,14 +10,37 @@ use rustc_target::callconv::{FnAbi, PassMode}; use crate::errors; -fn uses_vector_registers(mode: &PassMode, repr: &BackendRepr) -> bool { +/// Are vector registers used? +enum UsesVectorRegisters { + /// e.g. `neon` + FixedVector, + /// e.g. `sve` + ScalableVector, + No, +} + +/// Determines whether the combination of `mode` and `repr` will use fixed vector registers, +/// scalable vector registers or no vector registers. +fn uses_vector_registers(mode: &PassMode, repr: &BackendRepr) -> UsesVectorRegisters { match mode { - PassMode::Ignore | PassMode::Indirect { .. } => false, - PassMode::Cast { pad_i32: _, cast } => { - cast.prefix.iter().any(|r| r.is_some_and(|x| x.kind == RegKind::Vector)) - || cast.rest.unit.kind == RegKind::Vector + PassMode::Ignore | PassMode::Indirect { .. } => UsesVectorRegisters::No, + PassMode::Cast { pad_i32: _, cast } + if cast.prefix.iter().any(|r| r.is_some_and(|x| x.kind == RegKind::Vector)) + || cast.rest.unit.kind == RegKind::Vector => + { + UsesVectorRegisters::FixedVector + } + PassMode::Direct(..) | PassMode::Pair(..) + if matches!(repr, BackendRepr::SimdVector { .. }) => + { + UsesVectorRegisters::FixedVector } - PassMode::Direct(..) | PassMode::Pair(..) => matches!(repr, BackendRepr::SimdVector { .. }), + PassMode::Direct(..) | PassMode::Pair(..) + if matches!(repr, BackendRepr::ScalableVector { .. }) => + { + UsesVectorRegisters::ScalableVector + } + _ => UsesVectorRegisters::No, } } @@ -32,37 +55,64 @@ fn do_check_simd_vector_abi<'tcx>( is_call: bool, loc: impl Fn() -> (Span, HirId), ) { - let feature_def = tcx.sess.target.features_for_correct_vector_abi(); + tracing::debug!(?def_id); let codegen_attrs = tcx.codegen_fn_attrs(def_id); let have_feature = |feat: Symbol| { - tcx.sess.unstable_target_features.contains(&feat) - || codegen_attrs.target_features.iter().any(|x| x.name == feat) + let target_feats = tcx.sess.unstable_target_features.contains(&feat); + let fn_feats = codegen_attrs.target_features.iter().any(|x| x.name == feat); + tracing::debug!(?target_feats, ?fn_feats); + target_feats || fn_feats }; for arg_abi in abi.args.iter().chain(std::iter::once(&abi.ret)) { + tracing::debug!(?arg_abi); let size = arg_abi.layout.size; - if uses_vector_registers(&arg_abi.mode, &arg_abi.layout.backend_repr) { - // Find the first feature that provides at least this vector size. - let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) { - Some((_, feature)) => feature, - None => { + match uses_vector_registers(&arg_abi.mode, &arg_abi.layout.backend_repr) { + UsesVectorRegisters::FixedVector => { + let feature_def = tcx.sess.target.features_for_correct_fixed_length_vector_abi(); + // Find the first feature that provides at least this vector size. + let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) { + Some((_, feature)) => feature, + None => { + let (span, _hir_id) = loc(); + tcx.dcx().emit_err(errors::AbiErrorUnsupportedVectorType { + span, + ty: arg_abi.layout.ty, + is_call, + }); + continue; + } + }; + if !have_feature(Symbol::intern(feature)) { let (span, _hir_id) = loc(); - tcx.dcx().emit_err(errors::AbiErrorUnsupportedVectorType { + tcx.dcx().emit_err(errors::AbiErrorDisabledVectorType { span, + required_feature: feature, ty: arg_abi.layout.ty, is_call, + is_scalable: false, }); + } + } + UsesVectorRegisters::ScalableVector => { + let Some(required_feature) = + tcx.sess.target.features_for_correct_scalable_vector_abi() + else { continue; + }; + tracing::debug!(?required_feature); + if !have_feature(Symbol::intern(required_feature)) { + let (span, _) = loc(); + tcx.dcx().emit_err(errors::AbiErrorDisabledVectorType { + span, + required_feature, + ty: arg_abi.layout.ty, + is_call, + is_scalable: true, + }); } - }; - if !have_feature(Symbol::intern(feature)) { - // Emit error. - let (span, _hir_id) = loc(); - tcx.dcx().emit_err(errors::AbiErrorDisabledVectorType { - span, - required_feature: feature, - ty: arg_abi.layout.ty, - is_call, - }); + } + UsesVectorRegisters::No => { + continue; } } } diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index c0bebdf6fb639..1361e410a58ad 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -174,6 +174,19 @@ where // "best effort" optimization and `{meta,pointee,}sized_constraint` may return `Some`, // even if the ADT is {meta,pointee,}sized for all possible args. ty::Adt(def, args) => { + // FIXME(repr_scalable): Scalable vectors aren't actually `Sized`. They will be + // non-const `Sized` after the `sized_hierarchy` feature is implemented, but until + // then need to act like `Sized` types - either by forcing it in the trait solver, + // as below, or by omitting the `Sized` constraints in the first place. Omitting the + // constraints would require many small changes throughout the compiler and in some + // cases would not be trivially limited to only the `repr(scalable)` types due + // to inference variables, etc. When `sized_hierarchy` is fully implemented, this + // line will be required anyway and will be correct, just that in the host effect + // builtin impl for sizedness, it won't be `const Sized`. + if def.is_scalable_vector() { + return Ok(ty::Binder::dummy(vec![])); + } + if let Some(crit) = def.sizedness_constraint(ecx.cx(), sizedness) { Ok(ty::Binder::dummy(vec![crit.instantiate(ecx.cx(), args)])) } else { diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 46c21dcf67b19..854c76a4455b8 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -605,6 +605,9 @@ passes_repr_align_should_be_align = passes_repr_conflicting = conflicting representation hints +passes_repr_scalable_without_simd = + `scalable` representation hint without `simd` representation hint + passes_rustc_allow_const_fn_unstable = attribute should be applied to `const fn` .label = not a `const fn` diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 7a73dd17e0c63..43e30e5c321ca 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1987,6 +1987,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let mut is_explicit_rust = false; let mut is_c = false; let mut is_simd = false; + let mut is_scalable = false; let mut is_transparent = false; for (repr, repr_span) in reprs { @@ -2055,6 +2056,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> { continue; } } + ReprAttr::ReprScalable(..) => { + is_scalable = true; + if target != Target::Struct { + self.dcx().emit_err(errors::AttrApplication::Struct { + hint_span: *repr_span, + span, + }); + } else { + continue; + } + } ReprAttr::ReprTransparent => { is_transparent = true; match target { @@ -2116,13 +2128,20 @@ impl<'tcx> CheckAttrVisitor<'tcx> { target: target.to_string(), }); } - if is_explicit_rust && (int_reprs > 0 || is_c || is_simd) { + if is_explicit_rust && (int_reprs > 0 || is_c || is_simd || is_scalable) { let hint_spans = hint_spans.clone().collect(); self.dcx().emit_err(errors::ReprConflicting { hint_spans }); } - // Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8) + // Warn on `repr(scalable(N))` w/out `repr(simd)` + // i.e. only `repr(simd, scalable(N))` permitted + if is_scalable && !is_simd { + let hint_spans = hint_spans.clone().collect(); + self.dcx().emit_err(errors::ReprScalableWithoutSimd { hint_spans }); + } + // Warn on repr(u8, u16), repr(C, simd), repr(C, scalable), and c-like-enum-repr(C, u8) if (int_reprs > 1) || (is_simd && is_c) + || (is_scalable && is_c) || (int_reprs == 1 && is_c && item.is_some_and(|item| { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 4ad615a2abfc8..f4c5c2941e086 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -611,6 +611,13 @@ pub(crate) struct ReprConflicting { pub hint_spans: Vec, } +#[derive(Diagnostic)] +#[diag(passes_repr_scalable_without_simd)] +pub(crate) struct ReprScalableWithoutSimd { + #[primary_span] + pub hint_spans: Vec, +} + #[derive(Diagnostic)] #[diag(passes_repr_align_greater_than_target_max, code = E0589)] #[note] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8b12edf426c1b..9b04d6b5a6a41 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1764,6 +1764,7 @@ symbols! { repr_align, repr_align_enum, repr_packed, + repr_scalable, repr_simd, repr_transparent, require, @@ -1923,6 +1924,7 @@ symbols! { saturating_add, saturating_div, saturating_sub, + scalable, sdylib, search_unbox, select_unpredictable, @@ -2002,6 +2004,7 @@ symbols! { simd_reduce_mul_unordered, simd_reduce_or, simd_reduce_xor, + simd_reinterpret, simd_relaxed_fma, simd_rem, simd_round, diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs index 27b41cc09ed0c..e9dc4dbf063f4 100644 --- a/compiler/rustc_target/src/callconv/loongarch.rs +++ b/compiler/rustc_target/src/callconv/loongarch.rs @@ -80,7 +80,10 @@ where } } }, - BackendRepr::SimdVector { .. } => return Err(CannotUseFpConv), + BackendRepr::SimdVector { .. } => { + return Err(CannotUseFpConv); + } + BackendRepr::ScalableVector { .. } => unreachable!(), BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields { FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index ab3271220eb47..a1c73b46d800c 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -391,6 +391,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> { ), BackendRepr::SimdVector { .. } => PassMode::Direct(ArgAttributes::new()), BackendRepr::Memory { .. } => Self::indirect_pass_mode(&layout), + BackendRepr::ScalableVector { .. } => PassMode::Direct(ArgAttributes::new()), }; ArgAbi { layout, mode } } diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs index a06f54d60e7b0..2efb3d870069b 100644 --- a/compiler/rustc_target/src/callconv/riscv.rs +++ b/compiler/rustc_target/src/callconv/riscv.rs @@ -91,7 +91,9 @@ where } } }, - BackendRepr::SimdVector { .. } => return Err(CannotUseFpConv), + BackendRepr::SimdVector { .. } | BackendRepr::ScalableVector { .. } => { + return Err(CannotUseFpConv); + } BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields { FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index 918b71c80c4f0..ce173d84c8d56 100644 --- a/compiler/rustc_target/src/callconv/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs @@ -98,6 +98,9 @@ where } false } + BackendRepr::ScalableVector { .. } => { + unreachable!("scalable vectors are unsupported") + } } } diff --git a/compiler/rustc_target/src/callconv/x86_64.rs b/compiler/rustc_target/src/callconv/x86_64.rs index d8db7ed6e4c0f..494c590dc63d3 100644 --- a/compiler/rustc_target/src/callconv/x86_64.rs +++ b/compiler/rustc_target/src/callconv/x86_64.rs @@ -59,6 +59,8 @@ where BackendRepr::SimdVector { .. } => Class::Sse, + BackendRepr::ScalableVector { .. } => panic!("scalable vectors are unsupported"), + BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => { for i in 0..layout.fields.count() { let field_off = off + layout.fields.offset(i); diff --git a/compiler/rustc_target/src/callconv/x86_win64.rs b/compiler/rustc_target/src/callconv/x86_win64.rs index 8f8597ea662a8..828eef7d04157 100644 --- a/compiler/rustc_target/src/callconv/x86_win64.rs +++ b/compiler/rustc_target/src/callconv/x86_win64.rs @@ -22,6 +22,7 @@ pub(crate) fn compute_abi_info(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<' // FIXME(eddyb) there should be a size cap here // (probably what clang calls "illegal vectors"). } + BackendRepr::ScalableVector { .. } => unreachable!("scalable vectors are unsupported"), BackendRepr::Scalar(scalar) => { if is_ret && matches!(scalar.primitive(), Primitive::Int(Integer::I128, _)) { if cx.target_spec().rustc_abi == Some(RustcAbi::X86Softfloat) { diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index b2af99228fe6d..63046c5b2fb86 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -797,17 +797,22 @@ pub fn all_rust_features() -> impl Iterator { // These arrays represent the least-constraining feature that is required for vector types up to a // certain size to have their "proper" ABI on each architecture. // Note that they must be kept sorted by vector size. -const X86_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = +const X86_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "sse"), (256, "avx"), (512, "avx512f")]; // FIXME: might need changes for AVX10. -const AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")]; +const AARCH64_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = + &[(128, "neon")]; // We might want to add "helium" too. -const ARM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")]; +const ARM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = + &[(128, "neon")]; -const POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "altivec")]; -const WASM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "simd128")]; -const S390X_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vector")]; -const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[ +const POWERPC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = + &[(128, "altivec")]; +const WASM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = + &[(128, "simd128")]; +const S390X_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = + &[(128, "vector")]; +const RISCV_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = &[ (32, "zvl32b"), (64, "zvl64b"), (128, "zvl128b"), @@ -822,13 +827,16 @@ const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[ (65536, "zvl65536b"), ]; // Always error on SPARC, as the necessary target features cannot be enabled in Rust at the moment. -const SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(64, "vis")*/]; +const SPARC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = + &[/*(64, "vis")*/]; -const HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = +const HEXAGON_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(512, "hvx-length64b"),*/ (1024, "hvx-length128b")]; -const MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "msa")]; -const CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vdspv1")]; -const LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = +const MIPS_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = + &[(128, "msa")]; +const CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = + &[(128, "vdspv1")]; +const LOONGARCH_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "lsx"), (256, "lasx")]; #[derive(Copy, Clone, Debug)] @@ -860,27 +868,38 @@ impl Target { } } - pub fn features_for_correct_vector_abi(&self) -> &'static [(u64, &'static str)] { + pub fn features_for_correct_fixed_length_vector_abi(&self) -> &'static [(u64, &'static str)] { match &*self.arch { - "x86" | "x86_64" => X86_FEATURES_FOR_CORRECT_VECTOR_ABI, - "aarch64" | "arm64ec" => AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI, - "arm" => ARM_FEATURES_FOR_CORRECT_VECTOR_ABI, - "powerpc" | "powerpc64" => POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI, - "loongarch32" | "loongarch64" => LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI, - "riscv32" | "riscv64" => RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI, - "wasm32" | "wasm64" => WASM_FEATURES_FOR_CORRECT_VECTOR_ABI, - "s390x" => S390X_FEATURES_FOR_CORRECT_VECTOR_ABI, - "sparc" | "sparc64" => SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI, - "hexagon" => HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI, - "mips" | "mips32r6" | "mips64" | "mips64r6" => MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI, + "x86" | "x86_64" => X86_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + "aarch64" | "arm64ec" => AARCH64_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + "arm" => ARM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + "powerpc" | "powerpc64" => POWERPC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + "loongarch32" | "loongarch64" => LOONGARCH_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + "riscv32" | "riscv64" => RISCV_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + "wasm32" | "wasm64" => WASM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + "s390x" => S390X_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + "sparc" | "sparc64" => SPARC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + "hexagon" => HEXAGON_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + "mips" | "mips32r6" | "mips64" | "mips64r6" => { + MIPS_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI + } "bpf" | "m68k" => &[], // no vector ABI - "csky" => CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI, + "csky" => CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, // FIXME: for some tier3 targets, we are overly cautious and always give warnings // when passing args in vector registers. _ => &[], } } + pub fn features_for_correct_scalable_vector_abi(&self) -> Option<&'static str> { + match &*self.arch { + "aarch64" | "arm64ec" => Some("sve"), + "riscv32" | "riscv64" => todo!(), + // Other targets have no scalable vectors. + _ => None, + } + } + pub fn tied_target_features(&self) -> &'static [&'static [&'static str]] { match &*self.arch { "aarch64" | "arm64ec" => AARCH64_TIED_FEATURES, diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 393f458bea273..8c6e6ae0637e4 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -66,6 +66,13 @@ pub fn type_allowed_to_implement_copy<'tcx>( _ => return Err(CopyImplementationError::NotAnAdt), }; + // Scalable vectors have an unsized field that would normally disallow a `Copy` impl on the + // type, but that type doesn't actually exist, it's just a marker to know the element type of + // the vector. After codegen, scalable vectors are just a register that can be trivially copied. + if adt.repr().scalable() { + return Ok(()); + } + all_fields_implement_trait( tcx, param_env, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 2e65750db25de..7da8ba5d2edd0 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2128,6 +2128,19 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ty::Pat(ty, _) => ty::Binder::dummy(vec![*ty]), ty::Adt(def, args) => { + // FIXME(repr_scalable): Scalable vectors aren't actually `Sized`. They will be + // non-const `Sized` after the `sized_hierarchy` feature is implemented, but until + // then need to act like `Sized` types - either by forcing it in the trait solver, + // as below, or by omitting the `Sized` constraints in the first place. Omitting the + // constraints would require many small changes throughout the compiler and in some + // cases would not be trivially limited to only the `repr(scalable)` types due + // to inference variables, etc. When `sized_hierarchy` is fully implemented, this + // line will be required anyway and will be correct, just that in the host effect + // builtin impl for sizedness, it won't be `const Sized`. + if def.repr().scalable() { + return ty::Binder::dummy(vec![]); + } + if let Some(crit) = def.sizedness_constraint(self.tcx(), sizedness) { ty::Binder::dummy(vec![crit.instantiate(self.tcx(), args)]) } else { diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index fed9f254cdf83..28323a14410f8 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -748,6 +748,13 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { ty::Array(subty, len) => { self.require_sized(subty, ObligationCauseCode::SliceOrArrayElem); + if subty.is_scalable_simd() && !self.span.is_dummy() { + self.tcx() + .dcx() + .struct_span_err(self.span, "scalable vectors cannot be array elements") + .emit(); + } + // Note that the len being WF is implicitly checked while visiting. // Here we just check that it's of type usize. let cause = self.cause(ObligationCauseCode::ArrayLen(t)); @@ -769,9 +776,25 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { } ty::Tuple(tys) => { - if let Some((_last, rest)) = tys.split_last() { + if let Some((last, rest)) = tys.split_last() { for &elem in rest { self.require_sized(elem, ObligationCauseCode::TupleElem); + if elem.is_scalable_simd() && !self.span.is_dummy() { + self.tcx() + .dcx() + .struct_span_err( + self.span, + "scalable vectors cannot be tuple fields", + ) + .emit(); + } + } + + if last.is_scalable_simd() && !self.span.is_dummy() { + self.tcx() + .dcx() + .struct_span_err(self.span, "scalable vectors cannot be tuple fields") + .emit(); } } } diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index f0ff50318abc8..2ff11368d2fe9 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -395,7 +395,9 @@ fn fn_abi_sanity_check<'tcx>( // `layout.backend_repr` and ignore everything else. We should just reject //`Aggregate` entirely here, but some targets need to be fixed first. match arg.layout.backend_repr { - BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => {} + BackendRepr::Scalar(_) + | BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } => {} BackendRepr::ScalarPair(..) => { panic!("`PassMode::Direct` used for ScalarPair type {}", arg.layout.ty) } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 163e2b3088374..0c39ad58a21aa 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -544,24 +544,30 @@ fn layout_of_uncached<'tcx>( // * #[repr(simd)] struct S([T; 4]) // // where T is a primitive scalar (integer/float/pointer). - let Some(ty::Array(e_ty, e_len)) = def + let f0_ty = def .is_struct() .then(|| &def.variant(FIRST_VARIANT).fields) .filter(|fields| fields.len() == 1) - .map(|fields| *fields[FieldIdx::ZERO].ty(tcx, args).kind()) - else { + .map(|fields| *fields[FieldIdx::ZERO].ty(tcx, args).kind()); + + let (e_ty, e_len) = if let Some(ty::Array(e_ty, e_len)) = f0_ty { + let e_len = extract_const_value(cx, ty, e_len)? + .try_to_target_usize(tcx) + .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; + (e_ty, e_len) + } else if let Some(ty::Slice(e_ty)) = f0_ty + && def.repr().scalable() + { + (e_ty, 1) + } else { // Invalid SIMD types should have been caught by typeck by now. let guar = tcx.dcx().delayed_bug("#[repr(simd)] was applied to an invalid ADT"); return Err(error(cx, LayoutError::ReferencesError(guar))); }; - let e_len = extract_const_value(cx, ty, e_len)? - .try_to_target_usize(tcx) - .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; - let e_ly = cx.layout_of(e_ty)?; - map_layout(cx.calc.simd_type(e_ly, e_len, def.repr().packed()))? + map_layout(cx.calc.simd_type(e_ly, e_len, def.repr().packed(), def.repr().scalable))? } // ADTs. diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs index 1311ee31182c6..85dbe3273594c 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -248,7 +248,7 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou // And the size has to be element * count plus alignment padding, of course assert!(size == (element_size * count).align_to(align)); } - BackendRepr::Memory { .. } => {} // Nothing to check. + BackendRepr::Memory { .. } | BackendRepr::ScalableVector { .. } => {} // Nothing to check. } } diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 2754d40fd36ce..180ea7295977e 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -597,6 +597,8 @@ pub trait AdtDef: Copy + Debug + Hash + Eq { fn is_struct(self) -> bool; + fn is_scalable_vector(self) -> bool; + /// Returns the type of the struct tail. /// /// Expects the `AdtDef` to be a struct. If it is not, then this will panic. diff --git a/compiler/stable_mir/src/abi.rs b/compiler/stable_mir/src/abi.rs index 7b0882caf1b3e..d7a9b5c84e907 100644 --- a/compiler/stable_mir/src/abi.rs +++ b/compiler/stable_mir/src/abi.rs @@ -233,6 +233,10 @@ pub enum ValueAbi { element: Scalar, count: u64, }, + ScalableVector { + element: Scalar, + count: u64, + }, Aggregate { /// If true, the size is exact, otherwise it's only a lower bound. sized: bool, @@ -243,7 +247,12 @@ impl ValueAbi { /// Returns `true` if the layout corresponds to an unsized type. pub fn is_unsized(&self) -> bool { match *self { - ValueAbi::Scalar(_) | ValueAbi::ScalarPair(..) | ValueAbi::Vector { .. } => false, + ValueAbi::Scalar(_) + | ValueAbi::ScalarPair(..) + | ValueAbi::Vector { .. } + // FIXME(repr_scalable): Scalable vectors are forced to be `Sized` while the + // `sized_hierarchy` feature is not yet fully implemented + | ValueAbi::ScalableVector { .. } => false, ValueAbi::Aggregate { sized } => !sized, } } diff --git a/compiler/stable_mir/src/unstable/convert/stable/abi.rs b/compiler/stable_mir/src/unstable/convert/stable/abi.rs index 8fdaa69c30526..8917303a7f158 100644 --- a/compiler/stable_mir/src/unstable/convert/stable/abi.rs +++ b/compiler/stable_mir/src/unstable/convert/stable/abi.rs @@ -256,6 +256,9 @@ impl<'tcx> Stable<'tcx> for rustc_abi::BackendRepr { rustc_abi::BackendRepr::SimdVector { element, count } => { ValueAbi::Vector { element: element.stable(tables, cx), count } } + rustc_abi::BackendRepr::ScalableVector { element, count } => { + ValueAbi::ScalableVector { element: element.stable(tables, cx), count } + } rustc_abi::BackendRepr::Memory { sized } => ValueAbi::Aggregate { sized }, } } diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index 19488082cc33d..d36283f81bc7e 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -216,6 +216,11 @@ pub unsafe fn simd_cast(x: T) -> U; #[rustc_nounwind] pub unsafe fn simd_as(x: T) -> U; +/// Replacement for `transmute`, specifically for use with scalable SIMD types. +#[rustc_intrinsic] +#[rustc_nounwind] +pub unsafe fn simd_reinterpret(src: Src) -> Dst; + /// Negates a vector elementwise. /// /// `T` must be a vector of integers or floats. diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs index b509e69b0d37b..02afebf65be9a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs @@ -6,30 +6,30 @@ use base_db::Crate; use cfg::{CfgExpr, CfgOptions}; use either::Either; use hir_expand::{ - HirFileId, InFile, - attrs::{Attr, AttrId, RawAttrs, collect_attrs}, + attrs::{collect_attrs, Attr, AttrId, RawAttrs}, span_map::SpanMapRef, + HirFileId, InFile, }; -use intern::{Symbol, sym}; +use intern::{sym, Symbol}; use la_arena::{ArenaMap, Idx, RawIdx}; use mbe::DelimiterKind; use rustc_abi::ReprOptions; use span::AstIdNode; use syntax::{ - AstPtr, ast::{self, HasAttrs}, + AstPtr, }; use triomphe::Arc; use tt::iter::{TtElement, TtIter}; use crate::{ - AdtId, AstIdLoc, AttrDefId, GenericParamId, HasModule, LocalFieldId, Lookup, MacroId, - VariantId, db::DefDatabase, item_tree::block_item_tree_query, lang_item::LangItem, nameres::{ModuleOrigin, ModuleSource}, src::{HasChildSource, HasSource}, + AdtId, AstIdLoc, AttrDefId, GenericParamId, HasModule, LocalFieldId, Lookup, MacroId, + VariantId, }; /// Desugared attributes of an item post `cfg_attr` expansion. @@ -199,7 +199,11 @@ impl Attrs { #[inline] pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> Result<(), CfgExpr> { self.cfgs().try_for_each(|cfg| { - if cfg_options.check(&cfg) != Some(false) { Ok(()) } else { Err(cfg) } + if cfg_options.check(&cfg) != Some(false) { + Ok(()) + } else { + Err(cfg) + } }) } @@ -331,7 +335,7 @@ fn parse_rustc_legacy_const_generics(tt: &crate::tt::TopSubtree) -> Box<[u32]> { } fn merge_repr(this: &mut ReprOptions, other: ReprOptions) { - let ReprOptions { int, align, pack, flags, field_shuffle_seed: _ } = this; + let ReprOptions { int, align, pack, flags, scalable, field_shuffle_seed: _ } = this; flags.insert(other.flags); *align = (*align).max(other.align); *pack = match (*pack, other.pack) { @@ -341,6 +345,9 @@ fn merge_repr(this: &mut ReprOptions, other: ReprOptions) { if other.int.is_some() { *int = other.int; } + if other.scalable.is_some() { + *scalable = other.scalable; + } } fn parse_repr_tt(tt: &crate::tt::TopSubtree) -> Option { @@ -852,8 +859,8 @@ mod tests { use hir_expand::span_map::{RealSpanMap, SpanMap}; use span::FileId; - use syntax::{AstNode, TextRange, ast}; - use syntax_bridge::{DocCommentDesugarMode, syntax_node_to_token_tree}; + use syntax::{ast, AstNode, TextRange}; + use syntax_bridge::{syntax_node_to_token_tree, DocCommentDesugarMode}; use crate::attr::{DocAtom, DocExpr}; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index 107da6a5af6d6..e7f8cd971c211 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -4,11 +4,11 @@ use std::fmt; use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy}; use hir_def::{ - LocalFieldId, StructId, layout::{ Float, Integer, LayoutCalculator, LayoutCalculatorError, LayoutData, Primitive, ReprOptions, Scalar, StructKind, TargetDataLayout, WrappingRange, }, + LocalFieldId, StructId, }; use la_arena::{Idx, RawIdx}; use rustc_abi::AddressSpace; @@ -17,11 +17,11 @@ use rustc_index::IndexVec; use triomphe::Arc; use crate::{ - Interner, ProjectionTy, Substitution, TraitEnvironment, Ty, consteval::try_const_usize, db::{HirDatabase, InternedClosure}, infer::normalize, utils::ClosureSubst, + Interner, ProjectionTy, Substitution, TraitEnvironment, Ty, }; pub(crate) use self::adt::layout_of_adt_cycle_result; @@ -123,6 +123,7 @@ fn layout_of_simd_ty( db: &dyn HirDatabase, id: StructId, repr_packed: bool, + repr_scalable: Option, subst: &Substitution, env: Arc, dl: &TargetDataLayout, @@ -146,7 +147,7 @@ fn layout_of_simd_ty( let e_ly = db.layout_of_ty(e_ty, env)?; let cx = LayoutCx::new(dl); - Ok(Arc::new(cx.calc.simd_type(e_ly, e_len, repr_packed)?)) + Ok(Arc::new(cx.calc.simd_type(e_ly, e_len, repr_packed, repr_scalable)?)) } pub fn layout_of_ty_query( @@ -168,7 +169,15 @@ pub fn layout_of_ty_query( let data = db.struct_signature(*s); let repr = data.repr.unwrap_or_default(); if repr.simd() { - return layout_of_simd_ty(db, *s, repr.packed(), subst, trait_env, &target); + return layout_of_simd_ty( + db, + *s, + repr.packed(), + repr.scalable, + subst, + trait_env, + &target, + ); } }; return db.layout_of_adt(*def, subst.clone(), trait_env); diff --git a/tests/codegen/simd/scalable.rs b/tests/codegen/simd/scalable.rs new file mode 100644 index 0000000000000..f10a7f7f42965 --- /dev/null +++ b/tests/codegen/simd/scalable.rs @@ -0,0 +1,53 @@ +//@ compile-flags: -C opt-level=2 +//@ edition: 2021 +//@ only-aarch64 + +#![crate_type = "lib"] +#![allow(incomplete_features, internal_features)] +#![feature(repr_simd, repr_scalable, simd_ffi, link_llvm_intrinsics)] + +#[derive(Copy, Clone)] +#[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..3dc10e3fb9f0c --- /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 vector 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..53240662ca27c --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-repr-scalable.stderr @@ -0,0 +1,12 @@ +error[E0658]: scalable vector types are experimental + --> $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/async.rs b/tests/ui/simd/scalable/async.rs new file mode 100644 index 0000000000000..2dbbded5547c3 --- /dev/null +++ b/tests/ui/simd/scalable/async.rs @@ -0,0 +1,45 @@ +//@ only-aarch64 +//@ edition:2021 + +#![allow(incomplete_features, internal_features)] +#![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: scalable vectors cannot be held over await points + let temp = another().await; + let y: svint32_t = simd_reinterpret(x); + } +} + +fn main() { + let _ = test_function(); +} diff --git a/tests/ui/simd/scalable/async.stderr b/tests/ui/simd/scalable/async.stderr new file mode 100644 index 0000000000000..b7ba6171a234b --- /dev/null +++ b/tests/ui/simd/scalable/async.stderr @@ -0,0 +1,8 @@ +error: scalable vectors cannot be held over await points + --> $DIR/async.rs:37:13 + | +LL | let x = svdup_n_s32(1); + | ^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/simd/scalable/closure-capture.rs b/tests/ui/simd/scalable/closure-capture.rs new file mode 100644 index 0000000000000..925d7a05335df --- /dev/null +++ b/tests/ui/simd/scalable/closure-capture.rs @@ -0,0 +1,51 @@ +//@ only-aarch64 + +#![allow(incomplete_features, internal_features)] +#![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)] +fn run(f: impl Fn() -> ()) { + f(); +} + +fn main() { + unsafe { + let a = svdup_n_s32(42); + run(move || { //~ ERROR: scalable vectors cannot be tuple fields + svxar_n_s32::<2>(a, a); + //~^ ERROR: cannot move out of `a` + //~| ERROR: cannot move out of `a` + }); + } +} diff --git a/tests/ui/simd/scalable/closure-capture.stderr b/tests/ui/simd/scalable/closure-capture.stderr new file mode 100644 index 0000000000000..cd513d84c73eb --- /dev/null +++ b/tests/ui/simd/scalable/closure-capture.stderr @@ -0,0 +1,29 @@ +error: scalable vectors cannot be tuple fields + --> $DIR/closure-capture.rs:45:9 + | +LL | run(move || { + | ^^^ + +error[E0507]: cannot move out of `a`, a captured variable in an `Fn` closure + --> $DIR/closure-capture.rs:46:30 + | +LL | let a = svdup_n_s32(42); + | - captured outer variable +LL | run(move || { + | ------- captured by this `Fn` closure +LL | svxar_n_s32::<2>(a, a); + | ^ move occurs because `a` has type `svint32_t`, which does not implement the `Copy` trait + +error[E0507]: cannot move out of `a`, a captured variable in an `Fn` closure + --> $DIR/closure-capture.rs:46:33 + | +LL | let a = svdup_n_s32(42); + | - captured outer variable +LL | run(move || { + | ------- captured by this `Fn` closure +LL | svxar_n_s32::<2>(a, a); + | ^ move occurs because `a` has type `svint32_t`, which does not implement the `Copy` trait + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/simd/scalable/copy-clone.rs b/tests/ui/simd/scalable/copy-clone.rs new file mode 100644 index 0000000000000..816c73a9e6246 --- /dev/null +++ b/tests/ui/simd/scalable/copy-clone.rs @@ -0,0 +1,32 @@ +//@ build-pass +//@ only-aarch64 +#![feature(link_llvm_intrinsics, repr_simd, repr_scalable, simd_ffi)] + +#[derive(Copy, Clone)] +#[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) } +} + +#[target_feature(enable = "sve")] +fn require_copy(t: T) {} + +#[target_feature(enable = "sve")] +fn test() { + unsafe { + let a = svdup_n_s32(1); + require_copy(a); + } +} + +fn main() {} diff --git a/tests/ui/simd/scalable/fn-trait.rs b/tests/ui/simd/scalable/fn-trait.rs new file mode 100644 index 0000000000000..924799c749314 --- /dev/null +++ b/tests/ui/simd/scalable/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: scalable vectors cannot be tuple fields +{ +} + +fn main() {} diff --git a/tests/ui/simd/scalable/fn-trait.stderr b/tests/ui/simd/scalable/fn-trait.stderr new file mode 100644 index 0000000000000..8945069b10f8c --- /dev/null +++ b/tests/ui/simd/scalable/fn-trait.stderr @@ -0,0 +1,8 @@ +error: scalable vectors cannot be tuple fields + --> $DIR/fn-trait.rs:10:8 + | +LL | T: Fn(ScalableSimdFloat), + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/simd/scalable/illformed-in-types.rs b/tests/ui/simd/scalable/illformed-in-types.rs new file mode 100644 index 0000000000000..89a1a13b42ecf --- /dev/null +++ b/tests/ui/simd/scalable/illformed-in-types.rs @@ -0,0 +1,54 @@ +//@ compile-flags: --crate-type=lib +#![feature(repr_simd, repr_scalable)] + +#[repr(simd, scalable(4))] +pub struct ScalableFloat { + _ty: [f32] +} + +trait WithAssocTy { + type Ty; +} + +impl WithAssocTy for ScalableFloat { + type Ty = Self; +} + +pub enum AsEnumField { + Scalable(ScalableFloat), //~ ERROR: scalable vectors cannot be fields of a variant +} + +pub struct AsStructField { + v: ScalableFloat, //~ ERROR: scalable vectors cannot be fields of a struct +} + +pub union AsUnionField { + v: ScalableFloat, +//~^ ERROR: scalable vectors cannot be fields of a union +//~^^ ERROR: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union +} + +pub enum IndirectAsEnumField { + Scalable(::Ty), //~ ERROR: scalable vectors cannot be fields of a variant +} + +pub struct IndirectAsStructField { + v: ::Ty, //~ ERROR: scalable vectors cannot be fields of a struct +} + +pub union IndirectAsUnionField { + v: ::Ty, +//~^ ERROR: scalable vectors cannot be fields of a union +//~^^ ERROR: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union +} + +fn foo() { + let x: [ScalableFloat; 2]; //~ ERROR: scalable vectors cannot be array elements + let y: (ScalableFloat, u32); //~ ERROR: scalable vectors cannot be tuple fields + let z: (u32, ScalableFloat); //~ ERROR: scalable vectors cannot be tuple fields + + // FIXME(repr-scalable): these should error too + let indirect_x: [::Ty; 2]; + let indirect_y: (::Ty, u32); + let indirect_z: (u32, ::Ty); +} diff --git a/tests/ui/simd/scalable/illformed-in-types.stderr b/tests/ui/simd/scalable/illformed-in-types.stderr new file mode 100644 index 0000000000000..486a521e3934f --- /dev/null +++ b/tests/ui/simd/scalable/illformed-in-types.stderr @@ -0,0 +1,81 @@ +error: scalable vectors cannot be fields of a variant + --> $DIR/illformed-in-types.rs:18:14 + | +LL | Scalable(ScalableFloat), + | ^^^^^^^^^^^^^ + +error: scalable vectors cannot be fields of a struct + --> $DIR/illformed-in-types.rs:22:8 + | +LL | v: ScalableFloat, + | ^^^^^^^^^^^^^ + +error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union + --> $DIR/illformed-in-types.rs:26:5 + | +LL | v: ScalableFloat, + | ^^^^^^^^^^^^^^^^ + | + = 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 | v: std::mem::ManuallyDrop, + | +++++++++++++++++++++++ + + +error: scalable vectors cannot be fields of a union + --> $DIR/illformed-in-types.rs:26:8 + | +LL | v: ScalableFloat, + | ^^^^^^^^^^^^^ + +error: scalable vectors cannot be fields of a variant + --> $DIR/illformed-in-types.rs:32:14 + | +LL | Scalable(::Ty), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: scalable vectors cannot be fields of a struct + --> $DIR/illformed-in-types.rs:36:8 + | +LL | v: ::Ty, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union + --> $DIR/illformed-in-types.rs:40:5 + | +LL | v: ::Ty, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 | v: std::mem::ManuallyDrop<::Ty>, + | +++++++++++++++++++++++ + + +error: scalable vectors cannot be fields of a union + --> $DIR/illformed-in-types.rs:40:8 + | +LL | v: ::Ty, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: scalable vectors cannot be array elements + --> $DIR/illformed-in-types.rs:46:12 + | +LL | let x: [ScalableFloat; 2]; + | ^^^^^^^^^^^^^^^^^^ + +error: scalable vectors cannot be tuple fields + --> $DIR/illformed-in-types.rs:47:12 + | +LL | let y: (ScalableFloat, u32); + | ^^^^^^^^^^^^^^^^^^^^ + +error: scalable vectors cannot be tuple fields + --> $DIR/illformed-in-types.rs:48:12 + | +LL | let z: (u32, ScalableFloat); + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 11 previous errors + +For more information about this error, try `rustc --explain E0740`. diff --git a/tests/ui/simd/scalable/illformed.rs b/tests/ui/simd/scalable/illformed.rs new file mode 100644 index 0000000000000..dfa0ce85546fe --- /dev/null +++ b/tests/ui/simd/scalable/illformed.rs @@ -0,0 +1,21 @@ +//@ compile-flags: --crate-type=lib +#![feature(repr_scalable, repr_simd)] + +#[repr(simd, scalable(4))] +struct NoFields {} //~ ERROR: scalable vectors must have a single field + +#[repr(simd, scalable(4))] +struct MultipleFields { //~ ERROR: scalable vectors cannot have multiple fields + _ty: [f32], //~ ERROR: the size for values of type `[f32]` cannot be known at compilation time + other: u32, +} + +#[repr(simd, scalable(4))] +struct WrongFieldType { //~ ERROR: the field of a scalable vector type must be a slice + _ty: String, +} + +#[repr(simd, scalable(4))] +struct WrongElementTy { //~ ERROR: element type of a scalable vector must be a primitive scalar + _ty: [String], +} diff --git a/tests/ui/simd/scalable/illformed.stderr b/tests/ui/simd/scalable/illformed.stderr new file mode 100644 index 0000000000000..a2eeec8ad62f8 --- /dev/null +++ b/tests/ui/simd/scalable/illformed.stderr @@ -0,0 +1,51 @@ +error: scalable vectors must have a single field + --> $DIR/illformed.rs:5:1 + | +LL | struct NoFields {} + | ^^^^^^^^^^^^^^^ + | + = help: scalable vector types' only field must be slice of a primitive scalar type + +error: scalable vectors cannot have multiple fields + --> $DIR/illformed.rs:8:1 + | +LL | struct MultipleFields { + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the size for values of type `[f32]` cannot be known at compilation time + --> $DIR/illformed.rs:9:10 + | +LL | _ty: [f32], + | ^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[f32]` + = note: only the last field of a struct may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | _ty: &[f32], + | + +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | _ty: Box<[f32]>, + | ++++ + + +error: the field of a scalable vector type must be a slice + --> $DIR/illformed.rs:14:1 + | +LL | struct WrongFieldType { + | ^^^^^^^^^^^^^^^^^^^^^ +LL | _ty: String, + | ----------- not a slice + +error: element type of a scalable vector must be a primitive scalar + --> $DIR/illformed.rs:19:1 + | +LL | struct WrongElementTy { + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: only `u*`, `i*`, `f*`, `*const`, `*mut` and `bool` types are accepted + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/simd/scalable/invalid.rs b/tests/ui/simd/scalable/invalid.rs new file mode 100644 index 0000000000000..38e9c3456e016 --- /dev/null +++ b/tests/ui/simd/scalable/invalid.rs @@ -0,0 +1,225 @@ +//@ edition: 2024 +#![allow(internal_features, unused_imports, unused_macros)] +#![feature(extern_types)] +#![feature(gen_blocks)] +#![feature(repr_scalable)] +#![feature(repr_simd)] +#![feature(stmt_expr_attributes)] +#![feature(trait_alias)] + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +extern crate std as other_std; + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +use std::vec::Vec; + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +static _X: u32 = 0; + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +const _Y: u32 = 0; + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +mod bar { +} + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +unsafe extern "C" { + #[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + static X: &'static u32; + #[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + type Y; + #[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + fn foo(); +} + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +type Foo = u32; + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +enum Bar<#[repr(simd, scalable(4))] T> { +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + #[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + Baz(std::marker::PhantomData), +} + +struct Qux { + #[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + field: u32, +} + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +union FooBar { + x: u32, + y: u32, +} + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +trait FooBaz { + #[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + type Foo; + #[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + const Bar: i32; + #[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + fn foo() {} +} + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +trait FooQux = FooBaz; + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +impl Bar { + #[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + fn foo() {} +} + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +impl FooBaz for Bar { + type Foo = u32; + const Bar: i32 = 3; +} + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +macro_rules! barqux { ($foo:tt) => { $foo }; } + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +fn barqux(#[repr(simd, scalable(4))] _x: u32) {} +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +//~^^^ ERROR: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +async fn async_foo() {} + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +gen fn gen_foo() {} + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +async gen fn async_gen_foo() {} + +fn main() { + let _x = #[repr(simd, scalable(4))] || { }; +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + let _y = #[repr(simd, scalable(4))] 3 + 4; +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + #[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + let _z = 3; + + match _z { + #[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + 1 => (), + _ => (), + } +} + +#[repr(transparent, simd, scalable(4))] //~ ERROR: transparent struct cannot have other repr hints +struct CombinedWithReprTransparent { + _ty: [f64], +} + +#[repr(Rust, simd, scalable(4))] //~ ERROR: conflicting representation hints +struct CombinedWithReprRust { + _ty: [f64], +} + +#[repr(C, simd, scalable(4))] +//~^ ERROR: conflicting representation hints +//~^^ WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +struct CombinedWithReprC { + _ty: [f64], +} + +#[repr(scalable(4))] //~ ERROR: `scalable` representation hint without `simd` representation hint +struct WithoutReprSimd { + _ty: [f64], +} + +#[repr(simd, scalable)] //~ ERROR: invalid `scalable(num)` attribute: `scalable` needs an argument +struct MissingArg { +//~^ ERROR: SIMD vector's only field must be an array + _ty: [f64], +} + +#[repr(simd, scalable("4"))] //~ ERROR: invalid `scalable(num)` attribute: `scalable` needs an argument +struct ArgNotLit { +//~^ ERROR: SIMD vector's only field must be an array + _ty: [f64], +} + +#[repr(simd, scalable(4, 2))] //~ ERROR: invalid `scalable(num)` attribute: `scalable` needs an argument +struct ArgMultipleLits { +//~^ ERROR: SIMD vector's only field must be an array + _ty: [f64], +} + +#[repr(simd, scalable = "4")] //~ ERROR: unrecognized representation hint +struct ArgKind { +//~^ ERROR: SIMD vector's only field must be an array + _ty: [f64], +} + +#[repr(simd, scalable(4))] +struct Okay { + _ty: [f64], +} diff --git a/tests/ui/simd/scalable/invalid.stderr b/tests/ui/simd/scalable/invalid.stderr new file mode 100644 index 0000000000000..ddbf805b42b1f --- /dev/null +++ b/tests/ui/simd/scalable/invalid.stderr @@ -0,0 +1,729 @@ +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/invalid.rs:135:11 + | +LL | fn barqux(#[repr(simd, scalable(4))] _x: u32) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: invalid `scalable(num)` attribute: `scalable` needs an argument + --> $DIR/invalid.rs:198:14 + | +LL | #[repr(simd, scalable)] + | ^^^^^^^^ help: supply an argument here: `scalable(...)` + +error: invalid `scalable(num)` attribute: `scalable` needs an argument + --> $DIR/invalid.rs:204:14 + | +LL | #[repr(simd, scalable("4"))] + | ^^^^^^^^^^^^^ help: supply an argument here: `scalable(...)` + +error: invalid `scalable(num)` attribute: `scalable` needs an argument + --> $DIR/invalid.rs:210:14 + | +LL | #[repr(simd, scalable(4, 2))] + | ^^^^^^^^^^^^^^ help: supply an argument here: `scalable(...)` + +error[E0552]: unrecognized representation hint + --> $DIR/invalid.rs:216:14 + | +LL | #[repr(simd, scalable = "4")] + | ^^^^^^^^^^^^^^ + | + = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:10:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | extern crate std as other_std; + | ------------------------------ not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:10:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | extern crate std as other_std; + | ------------------------------ not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:15:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | use std::vec::Vec; + | ------------------ not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:15:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | use std::vec::Vec; + | ------------------ not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:20:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | static _X: u32 = 0; + | ------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:20:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | static _X: u32 = 0; + | ------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:25:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | const _Y: u32 = 0; + | ------------------ not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:25:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | const _Y: u32 = 0; + | ------------------ not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:30:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | / mod bar { +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:30:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | / mod bar { +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:36:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | / unsafe extern "C" { +LL | | #[repr(simd, scalable(4))] +... | +LL | | fn foo(); +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:36:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | / unsafe extern "C" { +LL | | #[repr(simd, scalable(4))] +... | +LL | | fn foo(); +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:54:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | type Foo = u32; + | --------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:54:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | type Foo = u32; + | --------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:59:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | / enum Bar<#[repr(simd, scalable(4))] T> { +LL | | +LL | | +LL | | #[repr(simd, scalable(4))] +... | +LL | | Baz(std::marker::PhantomData), +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:59:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | / enum Bar<#[repr(simd, scalable(4))] T> { +LL | | +LL | | +LL | | #[repr(simd, scalable(4))] +... | +LL | | Baz(std::marker::PhantomData), +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:62:17 + | +LL | enum Bar<#[repr(simd, scalable(4))] T> { + | ^^^^ - not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:62:23 + | +LL | enum Bar<#[repr(simd, scalable(4))] T> { + | ^^^^^^^^^^^ - not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:65:12 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | Baz(std::marker::PhantomData), + | -------------------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:65:18 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | Baz(std::marker::PhantomData), + | -------------------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:72:12 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | field: u32, + | ---------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:72:18 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | field: u32, + | ---------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:78:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | / union FooBar { +LL | | x: u32, +LL | | y: u32, +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:78:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | / union FooBar { +LL | | x: u32, +LL | | y: u32, +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:86:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | / trait FooBaz { +LL | | #[repr(simd, scalable(4))] +... | +LL | | fn foo() {} +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:86:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | / trait FooBaz { +LL | | #[repr(simd, scalable(4))] +... | +LL | | fn foo() {} +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:104:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | trait FooQux = FooBaz; + | ---------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:104:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | trait FooQux = FooBaz; + | ---------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:109:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | / impl Bar { +LL | | #[repr(simd, scalable(4))] +... | +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:109:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | / impl Bar { +LL | | #[repr(simd, scalable(4))] +... | +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:119:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | / impl FooBaz for Bar { +LL | | type Foo = u32; +LL | | const Bar: i32 = 3; +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:119:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | / impl FooBaz for Bar { +LL | | type Foo = u32; +LL | | const Bar: i32 = 3; +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:127:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | macro_rules! barqux { ($foo:tt) => { $foo }; } + | ---------------------------------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:127:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | macro_rules! barqux { ($foo:tt) => { $foo }; } + | ---------------------------------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:132:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | fn barqux(#[repr(simd, scalable(4))] _x: u32) {} + | ------------------------------------------------ not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:132:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | fn barqux(#[repr(simd, scalable(4))] _x: u32) {} + | ------------------------------------------------ not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:135:18 + | +LL | fn barqux(#[repr(simd, scalable(4))] _x: u32) {} + | -------^^^^----------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:135:24 + | +LL | fn barqux(#[repr(simd, scalable(4))] _x: u32) {} + | -------------^^^^^^^^^^^---------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:140:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | async fn async_foo() {} + | ----------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:140:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | async fn async_foo() {} + | ----------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:145:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | gen fn gen_foo() {} + | ------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:145:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | gen fn gen_foo() {} + | ------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:150:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | async gen fn async_gen_foo() {} + | ------------------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:150:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | async gen fn async_gen_foo() {} + | ------------------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:156:21 + | +LL | let _x = #[repr(simd, scalable(4))] || { }; + | ^^^^ ------ not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:156:27 + | +LL | let _x = #[repr(simd, scalable(4))] || { }; + | ^^^^^^^^^^^ ------ not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:159:21 + | +LL | let _y = #[repr(simd, scalable(4))] 3 + 4; + | ^^^^ - not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:159:27 + | +LL | let _y = #[repr(simd, scalable(4))] 3 + 4; + | ^^^^^^^^^^^ - not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:162:12 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | let _z = 3; + | ----------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:162:18 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | let _z = 3; + | ----------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:168:16 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | 1 => (), + | ------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:168:22 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | 1 => (), + | ------- not a struct + +error[E0692]: transparent struct cannot have other repr hints + --> $DIR/invalid.rs:176:8 + | +LL | #[repr(transparent, simd, scalable(4))] + | ^^^^^^^^^^^ ^^^^ ^^^^^^^^^^^ + +error[E0566]: conflicting representation hints + --> $DIR/invalid.rs:181:8 + | +LL | #[repr(Rust, simd, scalable(4))] + | ^^^^ ^^^^ ^^^^^^^^^^^ + +error[E0566]: conflicting representation hints + --> $DIR/invalid.rs:186:8 + | +LL | #[repr(C, simd, scalable(4))] + | ^ ^^^^ ^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #68585 + = note: `#[deny(conflicting_repr_hints)]` on by default + +error: `scalable` representation hint without `simd` representation hint + --> $DIR/invalid.rs:193:8 + | +LL | #[repr(scalable(4))] + | ^^^^^^^^^^^ + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:90:12 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | type Foo; + | --------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:90:18 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | type Foo; + | --------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:94:12 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | const Bar: i32; + | --------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:94:18 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | const Bar: i32; + | --------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:98:12 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | fn foo() {} + | ----------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:98:18 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | fn foo() {} + | ----------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:113:12 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | fn foo() {} + | ----------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:113:18 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | fn foo() {} + | ----------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:40:12 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | static X: &'static u32; + | ----------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:40:18 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | static X: &'static u32; + | ----------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:44:12 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | type Y; + | ------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:44:18 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | type Y; + | ------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:48:12 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | fn foo(); + | --------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:48:18 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | fn foo(); + | --------- not a struct + +error[E0076]: SIMD vector's only field must be an array + --> $DIR/invalid.rs:199:1 + | +LL | struct MissingArg { + | ^^^^^^^^^^^^^^^^^ +LL | +LL | _ty: [f64], + | ---------- not an array + +error[E0076]: SIMD vector's only field must be an array + --> $DIR/invalid.rs:205:1 + | +LL | struct ArgNotLit { + | ^^^^^^^^^^^^^^^^ +LL | +LL | _ty: [f64], + | ---------- not an array + +error[E0076]: SIMD vector's only field must be an array + --> $DIR/invalid.rs:211:1 + | +LL | struct ArgMultipleLits { + | ^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | _ty: [f64], + | ---------- not an array + +error[E0076]: SIMD vector's only field must be an array + --> $DIR/invalid.rs:217:1 + | +LL | struct ArgKind { + | ^^^^^^^^^^^^^^ +LL | +LL | _ty: [f64], + | ---------- not an array + +error: aborting due to 79 previous errors + +Some errors have detailed explanations: E0076, E0517, E0552, E0566, E0692. +For more information about an error, try `rustc --explain E0076`. +Future incompatibility report: Future breakage diagnostic: +error[E0566]: conflicting representation hints + --> $DIR/invalid.rs:186:8 + | +LL | #[repr(C, simd, scalable(4))] + | ^ ^^^^ ^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #68585 + = note: `#[deny(conflicting_repr_hints)]` on by default + diff --git a/tests/ui/simd/scalable/require-target-feature.rs b/tests/ui/simd/scalable/require-target-feature.rs new file mode 100644 index 0000000000000..74e1f2709de56 --- /dev/null +++ b/tests/ui/simd/scalable/require-target-feature.rs @@ -0,0 +1,42 @@ +//@ build-fail +//@ compile-flags: --crate-type=lib +//@ only-aarch64 +#![allow(incomplete_features, internal_features)] +#![feature( + repr_simd, + repr_scalable, + simd_ffi, + link_llvm_intrinsics +)] + +#[derive(Copy, Clone)] +#[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) } +} + +pub fn non_annotated_callee(x: svint32_t) {} +//~^ ERROR: this function definition uses scalable vector type `svint32_t` + +#[target_feature(enable = "sve")] +pub fn annotated_callee(x: svint32_t) {} // okay! + +#[target_feature(enable = "sve")] +pub fn caller() { + unsafe { + let a = svdup_n_s32(42); + non_annotated_callee(a); + annotated_callee(a); + } +} diff --git a/tests/ui/simd/scalable/require-target-feature.stderr b/tests/ui/simd/scalable/require-target-feature.stderr new file mode 100644 index 0000000000000..3df33dcf30832 --- /dev/null +++ b/tests/ui/simd/scalable/require-target-feature.stderr @@ -0,0 +1,10 @@ +error: this function definition uses scalable vector type `svint32_t` which (with the chosen ABI) requires the `sve` target feature, which is not enabled + --> $DIR/require-target-feature.rs:29:1 + | +LL | pub fn non_annotated_callee(x: svint32_t) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = help: consider enabling it globally (`-C target-feature=+sve`) or locally (`#[target_feature(enable="sve")]`) + +error: aborting due to 1 previous error + diff --git a/tests/ui/simd/scalable/value-type.rs b/tests/ui/simd/scalable/value-type.rs new file mode 100644 index 0000000000000..a4c0f24f4d71a --- /dev/null +++ b/tests/ui/simd/scalable/value-type.rs @@ -0,0 +1,30 @@ +//@ build-pass +//@ compile-flags: --crate-type=lib +//@ only-aarch64 +#![feature(link_llvm_intrinsics, simd_ffi, repr_scalable, repr_simd)] + +#[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) } +} + +// Tests that scalable vectors can be locals, arguments and return types. + +fn id(v: svint32_t) -> svint32_t { v } + +fn foo() { + unsafe { + let v = svdup_n_s32(1); + let v = id(v); + } +} diff --git a/tests/ui/simd/scalable/wellformed.rs b/tests/ui/simd/scalable/wellformed.rs new file mode 100644 index 0000000000000..2237174df40f0 --- /dev/null +++ b/tests/ui/simd/scalable/wellformed.rs @@ -0,0 +1,68 @@ +//@ check-pass +//@ compile-flags: --crate-type=lib +#![feature(repr_scalable, repr_simd)] + +#[repr(simd, scalable(4))] +struct ScalableU8 { + _ty: [u8], +} + +#[repr(simd, scalable(4))] +struct ScalableU16 { + _ty: [u16], +} + +#[repr(simd, scalable(4))] +struct ScalableU32 { + _ty: [u32], +} + +#[repr(simd, scalable(4))] +struct ScalableU64 { + _ty: [u64], +} + +#[repr(simd, scalable(4))] +struct ScalableI8 { + _ty: [i8], +} + +#[repr(simd, scalable(4))] +struct ScalableI16 { + _ty: [i16], +} + +#[repr(simd, scalable(4))] +struct ScalableI32 { + _ty: [i32], +} + +#[repr(simd, scalable(4))] +struct ScalableI64 { + _ty: [i64], +} + +#[repr(simd, scalable(4))] +struct ScalableF32 { + _ty: [f32], +} + +#[repr(simd, scalable(4))] +struct ScalableF64 { + _ty: [f64], +} + +#[repr(simd, scalable(4))] +struct ScalableBool { + _ty: [bool], +} + +#[repr(simd, scalable(4))] +struct ScalableConstPtr { + _ty: [*const u8], +} + +#[repr(simd, scalable(4))] +struct ScalableMutPtr { + _ty: [*mut u8], +} diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout index 910582ae4d9e9..88ca75c9b98dc 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])), safety: Safe, value: None }], 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])), safety: Safe, value: None }], 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])), safety: Safe, value: None }], 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: []