diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 815edcc0dc4b9..0608c1b49e44c 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -231,7 +231,8 @@ pub trait LayoutCalculator { hide_niches(a); hide_niches(b); } - Abi::Vector { element, count: _ } => hide_niches(element), + Abi::Vector { element, .. } => hide_niches(element), + Abi::ScalableVector { element, .. } => hide_niches(element), Abi::Aggregate { sized: _ } => {} } st.largest_niche = None; diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index eb42803f93e4e..4039a327ad9de 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -41,9 +41,11 @@ bitflags! { // If true, the type's layout can be randomized using // the seed stored in `ReprOptions.layout_seed` const RANDOMIZE_LAYOUT = 1 << 4; + const IS_SCALABLE = 1 << 5; // Any of these flags being set prevent field reordering optimisation. const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits | ReprFlags::IS_SIMD.bits + | ReprFlags::IS_SCALABLE.bits | ReprFlags::IS_LINEAR.bits; } } @@ -76,6 +78,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 @@ -92,6 +95,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) @@ -1243,6 +1251,10 @@ pub enum Abi { Uninhabited, Scalar(Scalar), ScalarPair(Scalar, Scalar), + ScalableVector { + element: Scalar, + elt: u64, + }, Vector { element: Scalar, count: u64, @@ -1260,6 +1272,7 @@ impl Abi { match *self { Abi::Uninhabited | Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false, Abi::Aggregate { sized } => !sized, + Abi::ScalableVector { .. } => true, } } @@ -1306,7 +1319,7 @@ impl Abi { Abi::Vector { element, count } => { cx.data_layout().vector_align(element.size(cx) * count) } - Abi::Uninhabited | Abi::Aggregate { .. } => return None, + Abi::Uninhabited | Abi::Aggregate { .. } | Abi::ScalableVector { .. } => return None, }) } @@ -1327,7 +1340,7 @@ impl Abi { // to make the size a multiple of align (e.g. for vectors of size 3). (element.size(cx) * count).align_to(self.inherent_align(cx)?.abi) } - Abi::Uninhabited | Abi::Aggregate { .. } => return None, + Abi::Uninhabited | Abi::Aggregate { .. } | Abi::ScalableVector { .. } => return None, }) } @@ -1337,6 +1350,9 @@ impl Abi { Abi::Scalar(s) => Abi::Scalar(s.to_union()), Abi::ScalarPair(s1, s2) => Abi::ScalarPair(s1.to_union(), s2.to_union()), Abi::Vector { element, count } => Abi::Vector { element: element.to_union(), count }, + Abi::ScalableVector { element, elt } => { + Abi::ScalableVector { element: element.to_union(), elt } + } Abi::Uninhabited | Abi::Aggregate { .. } => Abi::Aggregate { sized: true }, } } @@ -1620,6 +1636,11 @@ impl LayoutS { self.is_sized() && self.size.bytes() == 0 && self.align.abi.bytes() == 1 } + /// Returns true if the size of the type is only known at runtime. + pub fn is_runtime_sized(&self) -> bool { + matches!(self.abi, Abi::ScalableVector { .. }) + } + /// Returns `true` if the type is a ZST and not unsized. /// /// Note that this does *not* imply that the type is irrelevant for layout! It can still have @@ -1629,6 +1650,7 @@ impl LayoutS { Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false, Abi::Uninhabited => self.size.bytes() == 0, Abi::Aggregate { sized } => sized && self.size.bytes() == 0, + Abi::ScalableVector { .. } => false, } } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 8fb7c7de50c6d..373b76b59f65d 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -261,6 +261,15 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { "SIMD types are experimental and possibly buggy" ); } + + if item.has_name(sym::scalable) { + gate!( + &self, + repr_scalable, + attr.span, + "Scalable SIMD types are experimental and possibly buggy" + ); + } } } } diff --git a/compiler/rustc_attr/messages.ftl b/compiler/rustc_attr/messages.ftl index 7281282fec37d..9822e55e070ac 100644 --- a/compiler/rustc_attr/messages.ftl +++ b/compiler/rustc_attr/messages.ftl @@ -88,6 +88,9 @@ attr_rustc_allowed_unstable_pairing = attr_rustc_promotable_pairing = `rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute +attr_scalable_missing_n = + invalid `scalable(num)` attribute: `scalable` needs an argument + .suggestion = supply an argument here attr_soft_no_args = `soft` should not have any arguments diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 7e87d1c31301b..8a7193836b310 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -909,6 +909,7 @@ pub enum ReprAttr { ReprSimd, ReprTransparent, ReprAlign(u32), + ReprScalable(u32), } #[derive(Eq, PartialEq, Debug, Copy, Clone)] @@ -964,6 +965,13 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec { recognised = true; None } + sym::scalable => { + sess.emit_err(session_diagnostics::ScalableAttrMissingN { + span: item.span(), + }); + recognised = true; + None + } name => int_type_of_word(name).map(ReprInt), }; @@ -985,6 +993,12 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec { Ok(literal) => acc.push(ReprPacked(literal)), Err(message) => literal_error = Some(message), }; + } else if name == sym::scalable { + recognised = true; + match parse_scalable(&value.kind) { + Ok(literal) => acc.push(ReprScalable(literal)), + Err(message) => literal_error = Some(message), + }; } else if matches!(name, sym::C | sym::simd | sym::transparent) || int_type_of_word(name).is_some() { @@ -1004,7 +1018,10 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec { } else if let Some(meta_item) = item.meta_item() { match &meta_item.kind { MetaItemKind::NameValue(value) => { - if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) { + if meta_item.has_name(sym::align) + || meta_item.has_name(sym::packed) + || meta_item.has_name(sym::scalable) + { let name = meta_item.name_or_empty().to_ident_string(); recognised = true; sess.emit_err(session_diagnostics::IncorrectReprFormatGeneric { @@ -1199,3 +1216,11 @@ pub fn parse_confusables(attr: &Attribute) -> Option> { return Some(candidates); } + +pub fn parse_scalable(node: &ast::LitKind) -> Result { + if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node { + (*literal).try_into().map_err(|_| "integer too large") + } else { + Err("not an unsuffixed integer") + } +} diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index ca9bbd28b9556..95a729bb2b387 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -390,3 +390,11 @@ pub(crate) struct UnknownVersionLiteral { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(attr_scalable_missing_n, code = "E0796")] +pub(crate) struct ScalableAttrMissingN { + #[primary_span] + #[suggestion(applicability = "has-placeholders", code = "scalable(...)")] + pub span: Span, +} diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index fdc710c4b4f32..5a021abff1beb 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -515,7 +515,15 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { place_ty = self.sanitize_projection(place_ty, elem, place, location, context); } - if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { + // The Copy trait isn't implemented for scalable SIMD types. + // These types live somewhere between `Sized` and `Unsize`. + // The bounds on `Copy` disallow the trait from being + // implemented for them. As a result of this no bounds from + // `Copy` apply for the type, therefore, skipping this check + // should be perfectly legal. + if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context + && !place_ty.ty.is_scalable_simd() + { let tcx = self.tcx(); let trait_ref = ty::TraitRef::from_lang_item(tcx, LangItem::Copy, self.last_span, [place_ty.ty]); @@ -1763,11 +1771,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // expressions evaluate through `as_temp` or `into` a return // slot or local, so to find all unsized rvalues it is enough // to check all temps, return slots and locals. - if self.reported_errors.replace((ty, span)).is_none() { - // While this is located in `nll::typeck` this error is not - // an NLL error, it's a required check to prevent creation - // of unsized rvalues in a call expression. - self.tcx().sess.emit_err(MoveUnsized { ty, span }); + if !ty.is_scalable_simd() { + if self.reported_errors.replace((ty, span)).is_none() { + // While this is located in `nll::typeck` this error is not + // an NLL error, it's a required check to prevent creation + // of unsized rvalues in a call expression. + self.tcx().sess.emit_err(MoveUnsized { ty, span }); + } } } } diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index f601cd95f2a68..d7d972906f72b 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -94,6 +94,7 @@ impl GccType for Reg { } }, RegKind::Vector => unimplemented!(), //cx.type_vector(cx.type_i8(), self.size.bytes()), + RegKind::ScalableVector => unimplemented!(), } } } diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index f3a9ca77a67b1..be7ff1c957747 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -571,6 +571,13 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister { InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { unreachable!("clobber-only") } + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::zreg) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::zreg_low16) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::zreg_low8) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg_low8) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::ffr_reg) => { + unimplemented() + }, InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => "r", InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16) @@ -647,9 +654,14 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister { fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegClass) -> Type<'gcc> { match reg { InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => cx.type_i32(), - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => unimplemented!(), InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) - | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => { + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::zreg) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::zreg_low16) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::zreg_low8) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg_low8) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::ffr_reg) => { unimplemented!() } InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg)=> cx.type_i32(), @@ -791,6 +803,13 @@ fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { unreachable!("clobber-only") } + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::zreg) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::zreg_low16) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::zreg_low8) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg_low8) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::ffr_reg) => { + unsupported(); + } InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => None, InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => None, diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index ba1cae03f3e41..8a740921ee927 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -274,7 +274,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { let layout = self.layout_of(tp_ty).layout; let _use_integer_compare = match layout.abi() { Scalar(_) | ScalarPair(_, _) => true, - Uninhabited | Vector { .. } => false, + Uninhabited | Vector { .. } | ScalableVector { .. } => false, Aggregate { .. } => { // For rusty ABIs, small aggregates are actually passed // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index 479a814788a54..9496faae00c10 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -80,6 +80,7 @@ fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout false, ); } + Abi::ScalableVector { .. } => todo!(), Abi::Uninhabited | Abi::Aggregate { .. } => {} } @@ -158,7 +159,7 @@ pub trait LayoutGccExt<'tcx> { impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { fn is_gcc_immediate(&self) -> bool { match self.abi { - Abi::Scalar(_) | Abi::Vector { .. } => true, + Abi::Scalar(_) | Abi::Vector { .. } | Abi::ScalableVector { .. } => true, Abi::ScalarPair(..) | Abi::Uninhabited | Abi::Aggregate { .. } => false, } } @@ -166,7 +167,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { fn is_gcc_scalar_pair(&self) -> bool { match self.abi { Abi::ScalarPair(..) => true, - Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } | Abi::Aggregate { .. } => false, + Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } | Abi::ScalableVector { .. } | Abi::Aggregate { .. } => false, } } diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index b5f53f5183835..2ee60314821e3 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -124,6 +124,7 @@ impl LlvmType for Reg { _ => bug!("unsupported float: {:?}", self), }, RegKind::Vector => cx.type_vector(cx.type_i8(), self.size.bytes()), + RegKind::ScalableVector => cx.type_scalable_vector(cx.type_i8(), 16), } } } diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 1323261ae9240..9668ccc94aaeb 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -213,9 +213,13 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { constraints.append(&mut clobbers); if !options.contains(InlineAsmOptions::PRESERVES_FLAGS) { match asm_arch { - InlineAsmArch::AArch64 | InlineAsmArch::Arm => { + InlineAsmArch::Arm => { constraints.push("~{cc}".to_string()); } + InlineAsmArch::AArch64 => { + constraints.push("~{cc}".to_string()); + constraints.push("~{ffr}".to_string()); + } InlineAsmArch::X86 | InlineAsmArch::X86_64 => { constraints.extend_from_slice(&[ "~{dirflag}".to_string(), @@ -616,6 +620,7 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> 4 => 's', 2 => 'h', 1 => 'd', // We fixup i8 to i8x8 + 0 => 'z', _ => unreachable!(), } } else { @@ -634,9 +639,15 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> // https://llvm.org/docs/LangRef.html#supported-constraint-code-list InlineAsmRegOrRegClass::RegClass(reg) => match reg { InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => "r", - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => "w", - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => "x", - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::zreg) => "w", + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::zreg_low16) => "x", + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::zreg_low8) => "y", + // @3 is required to inform LLVM that the modifier token is 3 characters long + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => "@3Upa", + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg_low8) => "@3Upl", + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::ffr_reg) => { unreachable!("clobber-only") } InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => "r", @@ -720,9 +731,14 @@ fn modifier_to_llvm( | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => { if modifier == Some('v') { None } else { modifier } } - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { - unreachable!("clobber-only") + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::zreg) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::zreg_low16) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::zreg_low8) => { + if modifier == Some('z') { None } else { modifier } } + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg_low8) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::ffr_reg) => None, InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => None, InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => None, @@ -810,7 +826,16 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &' | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => { cx.type_vector(cx.type_i64(), 2) } - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::zreg) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::zreg_low16) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::zreg_low8) => { + cx.type_scalable_vector(cx.type_i64(), 2) + } + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg_low8) => { + cx.type_scalable_vector(cx.type_bool(), 16) + } + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::ffr_reg) => { unreachable!("clobber-only") } InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => cx.type_i32(), diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 7b259055d40b5..3f06d4da42507 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -489,7 +489,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { #[instrument(level = "trace", skip(self))] fn load_operand(&mut self, place: PlaceRef<'tcx, &'ll Value>) -> OperandRef<'tcx, &'ll Value> { - assert_eq!(place.llextra.is_some(), place.layout.is_unsized()); + assert_eq!( + place.llextra.is_some(), + place.layout.is_unsized() && !place.layout.is_runtime_sized() + ); if place.layout.is_zst() { return OperandRef::zero_sized(place.layout); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index cf78fc56b498c..adac834ecede9 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1006,6 +1006,7 @@ fn build_struct_type_di_node<'ll, 'tcx>( Cow::Borrowed(f.name.as_str()) }; let field_layout = struct_type_and_layout.field(cx, i); + build_field_di_node( cx, owner, diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index cc7e78b9c62bf..3eca5a868be6a 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -302,6 +302,14 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { let use_integer_compare = match layout.abi() { Scalar(_) | ScalarPair(_, _) => true, Uninhabited | Vector { .. } => false, + ScalableVector { .. } => { + tcx.sess.emit_err(InvalidMonomorphization::NonScalableType { + span, + name: sym::raw_eq, + ty: tp_ty, + }); + return; + } Aggregate { .. } => { // For rusty ABIs, small aggregates are actually passed // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), @@ -983,6 +991,19 @@ 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); + + use rustc_codegen_ssa::mir::operand::OperandValue; + return Ok(match args[0].val { + OperandValue::Ref(val, _, _) | OperandValue::Immediate(val) => { + bx.bitcast(val, llret_ty) + } + OperandValue::ZeroSized => bx.const_undef(llret_ty), + OperandValue::Pair(_, _) => todo!(), + }); + } + // every intrinsic below takes a SIMD vector as its first argument let (in_len, in_elem) = require_simd!(arg_tys[0], SimdInput); let in_ty = arg_tys[0]; @@ -1176,12 +1197,16 @@ fn generic_simd_intrinsic<'ll, 'tcx>( InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len } ); match m_elem_ty.kind() { - ty::Int(_) => {} + ty::Int(_) | ty::Bool => {} _ => return_error!(InvalidMonomorphization::MaskType { span, name, ty: m_elem_ty }), } // truncate the mask to a vector of i1s let i1 = bx.type_i1(); - let i1xn = bx.type_vector(i1, m_len as u64); + let i1xn = if arg_tys[1].is_scalable_simd() { + bx.type_scalable_vector(i1, m_len as u64) + } else { + bx.type_vector(i1, m_len as u64) + }; let m_i1s = bx.trunc(args[0].immediate(), i1xn); return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate())); } @@ -1952,6 +1977,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( out_elem }); } + macro_rules! arith_binary { ($($name: ident: $($($p: ident),* => $call: ident),*;)*) => { $(if name == sym::$name { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 7fc02a95be0a9..dde5d3b72e1ea 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -882,6 +882,7 @@ extern "C" { pub fn LLVMRustArrayType(ElementType: &Type, ElementCount: u64) -> &Type; pub fn LLVMPointerTypeInContext(C: &Context, AddressSpace: c_uint) -> &Type; pub fn LLVMVectorType(ElementType: &Type, ElementCount: c_uint) -> &Type; + pub fn LLVMScalableVectorType(ElementType: &Type, ElementCount: c_uint) -> &Type; pub fn LLVMGetElementType(Ty: &Type) -> &Type; pub fn LLVMGetVectorSize(VectorTy: &Type) -> c_uint; diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 06b7703672fe8..afdda1b05eaa3 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -69,6 +69,10 @@ impl<'ll> CodegenCx<'ll, '_> { unsafe { llvm::LLVMVectorType(ty, len as c_uint) } } + pub(crate) fn type_scalable_vector(&self, ty: &'ll Type, len: u64) -> &'ll Type { + unsafe { llvm::LLVMScalableVectorType(ty, len as c_uint) } + } + pub(crate) fn func_params_types(&self, ty: &'ll Type) -> Vec<&'ll Type> { unsafe { let n_args = llvm::LLVMCountParamTypes(ty) as usize; diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 712b6ed533303..b0d094c8e7780 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -26,6 +26,15 @@ fn uncached_llvm_type<'a, 'tcx>( let element = layout.scalar_llvm_type_at(cx, element); return cx.type_vector(element, count); } + Abi::ScalableVector { ref element, elt } => { + let element = if element.is_bool() { + cx.type_i1() + } else { + layout.scalar_llvm_type_at(cx, *element) + }; + + return cx.type_scalable_vector(element, elt); + } Abi::ScalarPair(..) => { return cx.type_struct( &[ @@ -191,7 +200,7 @@ pub trait LayoutLlvmExt<'tcx> { impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { fn is_llvm_immediate(&self) -> bool { match self.abi { - Abi::Scalar(_) | Abi::Vector { .. } => true, + Abi::Scalar(_) | Abi::Vector { .. } | Abi::ScalableVector { .. } => true, Abi::ScalarPair(..) | Abi::Uninhabited | Abi::Aggregate { .. } => false, } } @@ -199,7 +208,11 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { fn is_llvm_scalar_pair(&self) -> bool { match self.abi { Abi::ScalarPair(..) => true, - Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } | Abi::Aggregate { .. } => false, + Abi::Uninhabited + | Abi::Scalar(_) + | Abi::Vector { .. } + | Abi::ScalableVector { .. } + | Abi::Aggregate { .. } => false, } } diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 5881c6236ece6..9a7ccaae94ccc 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -94,6 +94,7 @@ codegen_ssa_invalid_monomorphization_mask_type = invalid monomorphization of `{$ codegen_ssa_invalid_monomorphization_mismatched_lengths = invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}` +codegen_ssa_invalid_monomorphization_non_scalable_type = invalid monomorphization of `{$name}` intrinsic: expected non-scalable type, found scalable type `{$ty}` codegen_ssa_invalid_monomorphization_return_element = invalid monomorphization of `{$name}` intrinsic: expected return element type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` with element type `{$out_ty}` codegen_ssa_invalid_monomorphization_return_integer_type = invalid monomorphization of `{$name}` intrinsic: expected return type with integer elements, found `{$ret_ty}` with non-integer `{$out_ty}` diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index ed6ac9f9c5da8..c64d349ddc9ac 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1035,6 +1035,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 14915e816ee9b..d394e6e6b3d86 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -370,6 +370,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if attrs.flags.contains(CodegenFnAttrFlags::NAKED) { return; } + // FIXME: Don't spill scalable simd, this works for most of them however, + // some intermediate types can't be spilled e.g. `` + if operand.layout.ty.is_scalable_simd() { + return; + } Self::spill_operand_to_stack(*operand, name, bx) } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index a6fcf1fd38c1f..134c975e09a2f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -234,7 +234,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( if memory_locals.contains(local) { debug!("alloc: {:?} -> place", local); - if layout.is_unsized() { + if layout.is_unsized() && !layout.is_runtime_sized() { LocalRef::UnsizedPlace(PlaceRef::alloca_unsized_indirect(&mut start_bx, layout)) } else { LocalRef::Place(PlaceRef::alloca(&mut start_bx, layout)) diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 0ab2b7ecd9c80..d52ddb78c3aba 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -331,7 +331,10 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { bx.store(*llval, llptr, field.align.abi); *llval = bx.load(llfield_ty, llptr, field.align.abi); } - (OperandValue::Immediate(_), Abi::Uninhabited | Abi::Aggregate { sized: false }) => { + ( + OperandValue::Immediate(_), + Abi::Uninhabited | Abi::Aggregate { sized: false } | Abi::ScalableVector { .. }, + ) => { bug!() } (OperandValue::Pair(..), _) => bug!(), diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index eb590a45a63f2..261c0a39e6c01 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -29,7 +29,7 @@ pub struct PlaceRef<'tcx, V> { impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { pub fn new_sized(llval: V, layout: TyAndLayout<'tcx>) -> PlaceRef<'tcx, V> { - assert!(layout.is_sized()); + assert!(layout.is_runtime_sized() || !layout.is_unsized()); PlaceRef { llval, llextra: None, layout, align: layout.align.abi } } @@ -38,7 +38,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { layout: TyAndLayout<'tcx>, align: Align, ) -> PlaceRef<'tcx, V> { - assert!(layout.is_sized()); + assert!(layout.is_runtime_sized() || !layout.is_unsized()); PlaceRef { llval, llextra: None, layout, align } } @@ -56,7 +56,10 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { layout: TyAndLayout<'tcx>, align: Align, ) -> Self { - assert!(layout.is_sized(), "tried to statically allocate unsized place"); + assert!( + layout.is_runtime_sized() || !layout.is_unsized(), + "tried to statically allocate unsized place" + ); let tmp = bx.alloca(bx.cx().backend_type(layout), align); Self::new_sized_aligned(tmp, layout, align) } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 02b51dfe5bf7f..275f4e24bbd25 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -1021,6 +1021,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandValueKind::Immediate(match layout.abi { abi::Abi::Scalar(s) => s, abi::Abi::Vector { element, .. } => element, + abi::Abi::ScalableVector { element, .. } => element, x => span_bug!(self.mir.span, "Couldn't translate {x:?} as backend immediate"), }) } else if self.cx.is_backend_scalar_pair(layout) { diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index b1fde8e4d8638..a9b1ff047c75d 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -76,7 +76,7 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> { fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool { let param_env = ty::ParamEnv::reveal_all(); - if ty.is_sized(self.tcx(), param_env) { + if ty.is_sized(self.tcx(), param_env) || ty.is_scalable_simd() { return false; } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 20f251d5c91ad..29ed64f5a31a7 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -868,7 +868,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> self.visit_scalar(b, b_layout)?; } } - Abi::Vector { .. } => { + Abi::Vector { .. } | Abi::ScalableVector { .. } => { // No checks here, we assume layout computation gets this right. // (This is harder to check since Miri does not represent these as `Immediate`. We // also cannot use field projections since this might be a newtype around a vector.) diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index e9e0690f07df1..47d88abce9080 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -106,6 +106,7 @@ fn might_permit_raw_init_lax<'tcx>( Abi::Scalar(s) => scalar_allows_raw_init(s), Abi::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2), Abi::Vector { element: s, count } => count == 0 || scalar_allows_raw_init(s), + Abi::ScalableVector { element, .. } => scalar_allows_raw_init(element), Abi::Aggregate { .. } => true, // Fields are checked below. }; if !valid { diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 6680e8875c3e3..c9348e81532b1 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -515,6 +515,7 @@ E0792: include_str!("./error_codes/E0792.md"), E0793: include_str!("./error_codes/E0793.md"), E0794: include_str!("./error_codes/E0794.md"), E0795: include_str!("./error_codes/E0795.md"), +E0796: include_str!("./error_codes/E0796.md"), } // Undocumented removed error codes. Note that many removed error codes are kept in the list above diff --git a/compiler/rustc_error_codes/src/error_codes/E0796.md b/compiler/rustc_error_codes/src/error_codes/E0796.md new file mode 100644 index 0000000000000..b106af7cac96c --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0796.md @@ -0,0 +1,10 @@ +No value of `N` was specified for `repr(scalable(N))` + +Erroneous code example: + +```compile_fail,E0796 +#[repr(scalable)] +struct Foo { + _ty: [i32; 0], +} +``` diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index b11b190bdedad..b3f4f753cb44e 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -199,6 +199,8 @@ declare_features! ( (internal, prelude_import, "1.2.0", None, None), /// Used to identify crates that contain the profiler runtime. (internal, profiler_runtime, "1.18.0", None, None), + /// Allows the use of scalable SIMD types. + (unstable, repr_scalable, "CURRENT_RUSTC_VERSION", None, None), /// Allows using `rustc_*` attributes (RFC 572). (internal, rustc_attrs, "1.0.0", None, None), /// Allows using the `#[stable]` and `#[unstable]` attributes. diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index e301f0b22ef77..8875440ba9a6f 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -78,7 +78,7 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) { def.destructor(tcx); // force the destructor to be evaluated if def.repr().simd() { - check_simd(tcx, span, def_id); + check_simd(tcx, span, def_id, def.repr().scalable()); } check_transparent(tcx, def); @@ -831,13 +831,13 @@ fn check_impl_items_against_trait<'tcx>( } } -pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { +pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId, is_scalable: bool) { let t = tcx.type_of(def_id).instantiate_identity(); if let ty::Adt(def, args) = t.kind() && def.is_struct() { let fields = &def.non_enum_variant().fields; - if fields.is_empty() { + if fields.is_empty() && !is_scalable { struct_span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty").emit(); return; } @@ -855,7 +855,7 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { Some(fields.len() as u64) }; if let Some(len) = len { - if len == 0 { + if len == 0 && !is_scalable { struct_span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty").emit(); return; } else if len > MAX_SIMD_LANES { @@ -881,6 +881,7 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { ty::Array(t, _clen) if matches!(t.kind(), ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_)) => { /* struct([f32; 4]) is ok */ } + ty::Slice(_) if is_scalable => (), _ => { struct_span_err!( tcx.sess, diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 7ea21b24fc821..1bca703b5b4ca 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -525,6 +525,7 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) sym::simd_insert => (2, 0, vec![param(0), tcx.types.u32, param(1)], param(0)), sym::simd_extract => (2, 0, vec![param(0), tcx.types.u32], param(1)), sym::simd_cast + | sym::simd_reinterpret | sym::simd_as | sym::simd_cast_ptr | sym::simd_expose_addr diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index ba627c740dfce..0b7ca962a1f61 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -79,6 +79,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { return None; } } + ty::Slice(ty) if adt.repr().scalable() => (0 as u64, *ty), _ => (fields.len() as u64, elem_ty), }; @@ -106,6 +107,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { } ty::Float(FloatTy::F32) => Some(InlineAsmType::VecF32(size)), ty::Float(FloatTy::F64) => Some(InlineAsmType::VecF64(size)), + ty::Bool => Some(InlineAsmType::VecBool(size)), _ => None, } } diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index d13ae2c2094c9..109ed7962d580 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -122,7 +122,14 @@ pub(super) fn check_fn<'a, 'tcx>( hir::FnRetTy::DefaultReturn(_) => body.value.span, hir::FnRetTy::Return(ty) => ty.span, }; - fcx.require_type_is_sized(declared_ret_ty, return_or_body_span, traits::SizedReturnType); + + if !declared_ret_ty.is_scalable_simd() { + // Unsized locals and fn params have a feature gate to allow them. Return types don't + // with scalable vectors we need that feature, for now just remove the check for testing + // purposes. + fcx.require_type_is_sized(declared_ret_ty, return_or_body_span, traits::SizedReturnType); + } + fcx.check_return_expr(body.value, false); // We insert the deferred_coroutine_interiors entry after visiting the body. diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index a9f67f984da8e..d2f7afec009e1 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -583,7 +583,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { infer::BoundRegionConversionTime::FnCall, fn_sig.output(), ); - self.require_type_is_sized_deferred(output, expr.span, traits::SizedReturnType); + if !output.is_scalable_simd() { + // Unsized locals and fn params have a feature gate to allow them. Return types don't + // with scalable vectors we need to be able to return unsized types, for now just + // remove the check for testing purposes. + self.require_type_is_sized_deferred(output, expr.span, traits::SizedReturnType); + } } // We always require that the type provided as the value for @@ -3195,7 +3200,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_expr_asm_operand(&self, expr: &'tcx hir::Expr<'tcx>, is_input: bool) { let needs = if is_input { Needs::None } else { Needs::MutPlace }; let ty = self.check_expr_with_needs(expr, needs); - self.require_type_is_sized(ty, expr.span, traits::InlineAsmSized); + if !self.tcx.features().unsized_fn_params { + self.require_type_is_sized(ty, expr.span, traits::InlineAsmSized); + } if !is_input && !expr.is_syntactic_place_expr() { let mut err = self.tcx.sess.struct_span_err(expr.span, "invalid asm output"); diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 66a0f4ed9def6..ed03b9e79b2f2 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -265,7 +265,10 @@ fn typeck_with_fallback<'tcx>( for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) { let ty = fcx.normalize(span, ty); - fcx.require_type_is_sized(ty, span, code); + // ScalableSIMD: Justify this. + if !ty.is_scalable_simd() { + fcx.require_type_is_sized(ty, span, code); + } } fcx.select_obligations_where_possible(|_| {}); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 1d7abcf53ea3b..8868375a67ff6 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2049,6 +2049,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 @@ -2077,6 +2078,10 @@ impl<'tcx> TyCtxt<'tcx> { } attr::ReprTransparent => ReprFlags::IS_TRANSPARENT, attr::ReprSimd => ReprFlags::IS_SIMD, + attr::ReprScalable(e) => { + elt = Some(e); + ReprFlags::IS_SCALABLE + } attr::ReprInt(i) => { size = Some(match i { attr::IntType::SignedInt(x) => match x { @@ -2117,7 +2122,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 f12a512da3137..d53b97446e829 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2372,6 +2372,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, @@ -2388,6 +2396,12 @@ impl<'tcx> Ty<'tcx> { let f0_ty = variant.fields[FieldIdx::from_u32(0)].ty(tcx, args); match f0_ty.kind() { + Array(_, _) if def.repr().scalable() => { + bug!("Scalable SIMD should be using a slice, not array"); + } + Slice(f0_elem_ty) if def.repr().scalable() => { + (def.repr().scalable.unwrap_or(0) as u64, *f0_elem_ty) + } // If the first field is an array, we assume it is the only field and its // elements are the SIMD components. Array(f0_elem_ty, f0_len) => { @@ -2874,6 +2888,10 @@ impl<'tcx> Ty<'tcx> { /// This is mostly useful for optimizations, as these are the types /// on which we can replace cloning with dereferencing. pub fn is_trivially_pure_clone_copy(self) -> bool { + if self.is_scalable_simd() { + return true; + } + match self.kind() { ty::Bool | ty::Char | ty::Never => true, diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs index 744111edb84e4..b49470518d997 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs @@ -163,8 +163,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let ty = expr.ty; let param_env = this.param_env; - if !ty.is_sized(tcx, param_env) { - // !sized means !copy, so this is an unsized move + if !ty.is_sized(tcx, param_env) && !ty.is_scalable_simd() { + // !sized means !copy, so this is an unsized move. assert!(!ty.is_copy_modulo_regions(tcx, param_env)); // As described above, detect the case where we are passing a value of unsized diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index b882a038711c3..20203c7d58e46 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1036,7 +1036,7 @@ fn find_vtable_types_for_unsizing<'tcx>( let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| { let param_env = ty::ParamEnv::reveal_all(); let type_has_metadata = |ty: Ty<'tcx>| -> bool { - if ty.is_sized(tcx.tcx, param_env) { + if ty.is_sized(tcx.tcx, param_env) || ty.is_scalable_simd() { return false; } let tail = tcx.struct_tail_erasing_lifetimes(ty, param_env); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 4910d63010c6e..2f9c93d236664 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1852,6 +1852,9 @@ impl CheckAttrVisitor<'_> { continue; } } + sym::scalable => { + continue; + } sym::transparent => { is_transparent = true; match target { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index ea80bc82bd1f0..207f918dd6936 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -773,6 +773,7 @@ symbols! { ffi_const, ffi_pure, ffi_returns_twice, + ffr_reg, field, field_init_shorthand, file, @@ -1231,6 +1232,7 @@ symbols! { prefetch_write_data, prefetch_write_instruction, preg, + preg_low8, prelude, prelude_import, preserves_flags, @@ -1338,6 +1340,7 @@ symbols! { repr_align, repr_align_enum, repr_packed, + repr_scalable, repr_simd, repr_transparent, require, @@ -1480,6 +1483,7 @@ symbols! { saturating_add, saturating_div, saturating_sub, + scalable, self_in_typedefs, self_struct_ctor, semitransparent, @@ -1548,6 +1552,7 @@ symbols! { simd_reduce_mul_unordered, simd_reduce_or, simd_reduce_xor, + simd_reinterpret, simd_rem, simd_round, simd_saturating_add, @@ -1625,6 +1630,7 @@ symbols! { sub_assign, sub_with_overflow, suggestion, + sve, sym, sync, t32, @@ -1823,6 +1829,9 @@ symbols! { yield_expr, ymm_reg, zmm_reg, + zreg, + zreg_low16, + zreg_low8, } } diff --git a/compiler/rustc_target/src/abi/call/aarch64.rs b/compiler/rustc_target/src/abi/call/aarch64.rs index f99f6a3b72164..4655f69748a87 100644 --- a/compiler/rustc_target/src/abi/call/aarch64.rs +++ b/compiler/rustc_target/src/abi/call/aarch64.rs @@ -29,6 +29,7 @@ where RegKind::Integer => false, RegKind::Float => true, RegKind::Vector => size.bits() == 64 || size.bits() == 128, + RegKind::ScalableVector => true, }; valid_unit.then_some(Uniform { unit, total: size }) diff --git a/compiler/rustc_target/src/abi/call/arm.rs b/compiler/rustc_target/src/abi/call/arm.rs index 95f6691d42aeb..7de4796488fa2 100644 --- a/compiler/rustc_target/src/abi/call/arm.rs +++ b/compiler/rustc_target/src/abi/call/arm.rs @@ -19,6 +19,7 @@ where RegKind::Integer => false, RegKind::Float => true, RegKind::Vector => size.bits() == 64 || size.bits() == 128, + RegKind::ScalableVector => true, }; valid_unit.then_some(Uniform { unit, total: size }) diff --git a/compiler/rustc_target/src/abi/call/loongarch.rs b/compiler/rustc_target/src/abi/call/loongarch.rs index 647b6500c52dd..e9fcea51c42c5 100644 --- a/compiler/rustc_target/src/abi/call/loongarch.rs +++ b/compiler/rustc_target/src/abi/call/loongarch.rs @@ -76,7 +76,9 @@ where } } }, - Abi::Vector { .. } | Abi::Uninhabited => return Err(CannotUseFpConv), + Abi::Vector { .. } | Abi::ScalableVector { .. } | Abi::Uninhabited => { + return Err(CannotUseFpConv); + } Abi::ScalarPair(..) | Abi::Aggregate { .. } => match arg_layout.fields { FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index f7c860cf56b91..8ed80364dc2f9 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -182,6 +182,7 @@ pub enum RegKind { Integer, Float, Vector, + ScalableVector, } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] @@ -228,6 +229,7 @@ impl Reg { _ => panic!("unsupported float: {self:?}"), }, RegKind::Vector => dl.vector_align(self.size).abi, + RegKind::ScalableVector => dl.vector_align(self.size).abi, } } } @@ -384,7 +386,9 @@ impl HomogeneousAggregate { impl<'a, Ty> TyAndLayout<'a, Ty> { fn is_aggregate(&self) -> bool { match self.abi { - Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false, + Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } | Abi::ScalableVector { .. } => { + false + } Abi::ScalarPair(..) | Abi::Aggregate { .. } => true, } } @@ -422,6 +426,11 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { })) } + Abi::ScalableVector { .. } => Ok(HomogeneousAggregate::Homogeneous(Reg { + kind: RegKind::ScalableVector, + size: Size::from_bits(128), + })), + Abi::ScalarPair(..) | Abi::Aggregate { sized: true } => { // Helper for computing `homogeneous_aggregate`, allowing a custom // starting offset (used below for handling variants). @@ -557,6 +566,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> { ), Abi::Vector { .. } => PassMode::Direct(ArgAttributes::new()), Abi::Aggregate { .. } => Self::indirect_pass_mode(&layout), + Abi::ScalableVector { .. } => PassMode::Direct(ArgAttributes::new()), }; ArgAbi { layout, mode } } diff --git a/compiler/rustc_target/src/abi/call/powerpc64.rs b/compiler/rustc_target/src/abi/call/powerpc64.rs index 2d41f77e50e1e..74aeffd614e8d 100644 --- a/compiler/rustc_target/src/abi/call/powerpc64.rs +++ b/compiler/rustc_target/src/abi/call/powerpc64.rs @@ -35,6 +35,7 @@ where RegKind::Integer => false, RegKind::Float => true, RegKind::Vector => arg.layout.size.bits() == 128, + RegKind::ScalableVector => true, }; valid_unit.then_some(Uniform { unit, total: arg.layout.size }) diff --git a/compiler/rustc_target/src/abi/call/riscv.rs b/compiler/rustc_target/src/abi/call/riscv.rs index cbde234d34cc2..19b5198e08c67 100644 --- a/compiler/rustc_target/src/abi/call/riscv.rs +++ b/compiler/rustc_target/src/abi/call/riscv.rs @@ -82,7 +82,9 @@ where } } }, - Abi::Vector { .. } | Abi::Uninhabited => return Err(CannotUseFpConv), + Abi::Vector { .. } | Abi::ScalableVector { .. } | Abi::Uninhabited => { + return Err(CannotUseFpConv); + } Abi::ScalarPair(..) | Abi::Aggregate { .. } => match arg_layout.fields { FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs index e9aedc3d28a1e..d5e38b1efe1b1 100644 --- a/compiler/rustc_target/src/abi/call/x86.rs +++ b/compiler/rustc_target/src/abi/call/x86.rs @@ -108,6 +108,9 @@ where } false } + Abi::ScalableVector { .. } => { + unreachable!("Scalable Vectors are unsupported on this target") + } } } diff --git a/compiler/rustc_target/src/abi/call/x86_64.rs b/compiler/rustc_target/src/abi/call/x86_64.rs index 6c34585a11b82..2fbd85ebe469e 100644 --- a/compiler/rustc_target/src/abi/call/x86_64.rs +++ b/compiler/rustc_target/src/abi/call/x86_64.rs @@ -55,7 +55,7 @@ where }, Abi::Vector { .. } => Class::Sse, - + Abi::ScalableVector { .. } => panic!("Scalable vectors not supported"), Abi::ScalarPair(..) | Abi::Aggregate { .. } => { for i in 0..layout.fields.count() { let field_off = off + layout.fields.offset(i); diff --git a/compiler/rustc_target/src/abi/call/x86_win64.rs b/compiler/rustc_target/src/abi/call/x86_win64.rs index 90de1a42bc06b..fd42f85198197 100644 --- a/compiler/rustc_target/src/abi/call/x86_win64.rs +++ b/compiler/rustc_target/src/abi/call/x86_win64.rs @@ -18,6 +18,7 @@ pub fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { // FIXME(eddyb) there should be a size cap here // (probably what clang calls "illegal vectors"). } + Abi::ScalableVector { .. } => {} Abi::Scalar(_) => { if a.layout.size.bytes() > 8 { a.make_indirect(); diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs index 97132311a5c9a..d13a81724eb3b 100644 --- a/compiler/rustc_target/src/asm/aarch64.rs +++ b/compiler/rustc_target/src/asm/aarch64.rs @@ -10,7 +10,12 @@ def_reg_class! { reg, vreg, vreg_low16, + zreg, + zreg_low16, + zreg_low8, preg, + preg_low8, + ffr_reg, } } @@ -19,12 +24,26 @@ impl AArch64InlineAsmRegClass { match self { Self::reg => &['w', 'x'], Self::vreg | Self::vreg_low16 => &['b', 'h', 's', 'd', 'q', 'v'], - Self::preg => &[], + Self::zreg | Self::zreg_low16 | Self::zreg_low8 => &['b', 'h', 's', 'd', 'q', 'z'], + Self::preg | Self::preg_low8 => &['p'], + Self::ffr_reg => &[], } } - pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option { - None + pub fn suggest_class(self, _arch: InlineAsmArch, ty: InlineAsmType) -> Option { + if ty.size().bytes() == 0 { + match self { + Self::vreg => Some(Self::zreg), + Self::vreg_low16 => Some(Self::zreg_low16), + _ => None, + } + } else { + match self { + Self::zreg | Self::zreg_low8 => Some(Self::vreg), + Self::zreg_low16 => Some(Self::vreg_low16), + _ => None, + } + } } pub fn suggest_modifier( @@ -37,15 +56,19 @@ impl AArch64InlineAsmRegClass { 64 => None, _ => Some(('w', "w0")), }, - Self::vreg | Self::vreg_low16 => match ty.size().bits() { - 8 => Some(('b', "b0")), - 16 => Some(('h', "h0")), - 32 => Some(('s', "s0")), - 64 => Some(('d', "d0")), - 128 => Some(('q', "q0")), - _ => None, - }, - Self::preg => None, + Self::vreg | Self::vreg_low16 | Self::zreg | Self::zreg_low16 | Self::zreg_low8 => { + match ty.size().bits() { + 8 => Some(('b', "b0")), + 16 => Some(('h', "h0")), + 32 => Some(('s', "s0")), + 64 => Some(('d', "d0")), + 128 => Some(('q', "q0")), + _ => None, + } + } + + Self::preg | Self::preg_low8 => None, + Self::ffr_reg => None, } } @@ -53,7 +76,9 @@ impl AArch64InlineAsmRegClass { match self { Self::reg => Some(('x', "x0")), Self::vreg | Self::vreg_low16 => Some(('v', "v0")), - Self::preg => None, + Self::zreg | Self::zreg_low16 | Self::zreg_low8 => Some(('z', "z0")), + Self::preg | Self::preg_low8 => Some(('p', "p0")), + Self::ffr_reg => None, } } @@ -68,7 +93,15 @@ impl AArch64InlineAsmRegClass { VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2), VecF64(1), VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2); }, - Self::preg => &[], + Self::zreg => types! { + sve: I16, I32, I64, F32, F64, + VecI8(0), VecI16(0), VecI32(0), VecI64(0), VecF32(0), VecF64(0); + }, + Self::zreg_low16 | Self::zreg_low8 => types! { + sve: VecI8(0), VecI16(0), VecI32(0), VecI64(0), VecF32(0), VecF64(0); + }, + Self::preg | Self::preg_low8 => types! { sve: VecBool(0); }, + Self::ffr_reg => &[], } } } @@ -122,46 +155,78 @@ def_regs! { x27: reg = ["x27", "w27"], x28: reg = ["x28", "w28"], x30: reg = ["x30", "w30", "lr", "wlr"], - v0: vreg, vreg_low16 = ["v0", "b0", "h0", "s0", "d0", "q0", "z0"], - v1: vreg, vreg_low16 = ["v1", "b1", "h1", "s1", "d1", "q1", "z1"], - v2: vreg, vreg_low16 = ["v2", "b2", "h2", "s2", "d2", "q2", "z2"], - v3: vreg, vreg_low16 = ["v3", "b3", "h3", "s3", "d3", "q3", "z3"], - v4: vreg, vreg_low16 = ["v4", "b4", "h4", "s4", "d4", "q4", "z4"], - v5: vreg, vreg_low16 = ["v5", "b5", "h5", "s5", "d5", "q5", "z5"], - v6: vreg, vreg_low16 = ["v6", "b6", "h6", "s6", "d6", "q6", "z6"], - v7: vreg, vreg_low16 = ["v7", "b7", "h7", "s7", "d7", "q7", "z7"], - v8: vreg, vreg_low16 = ["v8", "b8", "h8", "s8", "d8", "q8", "z8"], - v9: vreg, vreg_low16 = ["v9", "b9", "h9", "s9", "d9", "q9", "z9"], - v10: vreg, vreg_low16 = ["v10", "b10", "h10", "s10", "d10", "q10", "z10"], - v11: vreg, vreg_low16 = ["v11", "b11", "h11", "s11", "d11", "q11", "z11"], - v12: vreg, vreg_low16 = ["v12", "b12", "h12", "s12", "d12", "q12", "z12"], - v13: vreg, vreg_low16 = ["v13", "b13", "h13", "s13", "d13", "q13", "z13"], - v14: vreg, vreg_low16 = ["v14", "b14", "h14", "s14", "d14", "q14", "z14"], - v15: vreg, vreg_low16 = ["v15", "b15", "h15", "s15", "d15", "q15", "z15"], - v16: vreg = ["v16", "b16", "h16", "s16", "d16", "q16", "z16"], - v17: vreg = ["v17", "b17", "h17", "s17", "d17", "q17", "z17"], - v18: vreg = ["v18", "b18", "h18", "s18", "d18", "q18", "z18"], - v19: vreg = ["v19", "b19", "h19", "s19", "d19", "q19", "z19"], - v20: vreg = ["v20", "b20", "h20", "s20", "d20", "q20", "z20"], - v21: vreg = ["v21", "b21", "h21", "s21", "d21", "q21", "z21"], - v22: vreg = ["v22", "b22", "h22", "s22", "d22", "q22", "z22"], - v23: vreg = ["v23", "b23", "h23", "s23", "d23", "q23", "z23"], - v24: vreg = ["v24", "b24", "h24", "s24", "d24", "q24", "z24"], - v25: vreg = ["v25", "b25", "h25", "s25", "d25", "q25", "z25"], - v26: vreg = ["v26", "b26", "h26", "s26", "d26", "q26", "z26"], - v27: vreg = ["v27", "b27", "h27", "s27", "d27", "q27", "z27"], - v28: vreg = ["v28", "b28", "h28", "s28", "d28", "q28", "z28"], - v29: vreg = ["v29", "b29", "h29", "s29", "d29", "q29", "z29"], - v30: vreg = ["v30", "b30", "h30", "s30", "d30", "q30", "z30"], - v31: vreg = ["v31", "b31", "h31", "s31", "d31", "q31", "z31"], - p0: preg = ["p0"], - p1: preg = ["p1"], - p2: preg = ["p2"], - p3: preg = ["p3"], - p4: preg = ["p4"], - p5: preg = ["p5"], - p6: preg = ["p6"], - p7: preg = ["p7"], + v0: vreg, vreg_low16 = ["v0", "b0", "h0", "s0", "d0", "q0"], + v1: vreg, vreg_low16 = ["v1", "b1", "h1", "s1", "d1", "q1"], + v2: vreg, vreg_low16 = ["v2", "b2", "h2", "s2", "d2", "q2"], + v3: vreg, vreg_low16 = ["v3", "b3", "h3", "s3", "d3", "q3"], + v4: vreg, vreg_low16 = ["v4", "b4", "h4", "s4", "d4", "q4"], + v5: vreg, vreg_low16 = ["v5", "b5", "h5", "s5", "d5", "q5"], + v6: vreg, vreg_low16 = ["v6", "b6", "h6", "s6", "d6", "q6"], + v7: vreg, vreg_low16 = ["v7", "b7", "h7", "s7", "d7", "q7"], + v8: vreg, vreg_low16 = ["v8", "b8", "h8", "s8", "d8", "q8"], + v9: vreg, vreg_low16 = ["v9", "b9", "h9", "s9", "d9", "q9"], + v10: vreg, vreg_low16 = ["v10", "b10", "h10", "s10", "d10", "q10"], + v11: vreg, vreg_low16 = ["v11", "b11", "h11", "s11", "d11", "q11"], + v12: vreg, vreg_low16 = ["v12", "b12", "h12", "s12", "d12", "q12"], + v13: vreg, vreg_low16 = ["v13", "b13", "h13", "s13", "d13", "q13"], + v14: vreg, vreg_low16 = ["v14", "b14", "h14", "s14", "d14", "q14"], + v15: vreg, vreg_low16 = ["v15", "b15", "h15", "s15", "d15", "q15"], + v16: vreg = ["v16", "b16", "h16", "s16", "d16", "q16"], + v17: vreg = ["v17", "b17", "h17", "s17", "d17", "q17"], + v18: vreg = ["v18", "b18", "h18", "s18", "d18", "q18"], + v19: vreg = ["v19", "b19", "h19", "s19", "d19", "q19"], + v20: vreg = ["v20", "b20", "h20", "s20", "d20", "q20"], + v21: vreg = ["v21", "b21", "h21", "s21", "d21", "q21"], + v22: vreg = ["v22", "b22", "h22", "s22", "d22", "q22"], + v23: vreg = ["v23", "b23", "h23", "s23", "d23", "q23"], + v24: vreg = ["v24", "b24", "h24", "s24", "d24", "q24"], + v25: vreg = ["v25", "b25", "h25", "s25", "d25", "q25"], + v26: vreg = ["v26", "b26", "h26", "s26", "d26", "q26"], + v27: vreg = ["v27", "b27", "h27", "s27", "d27", "q27"], + v28: vreg = ["v28", "b28", "h28", "s28", "d28", "q28"], + v29: vreg = ["v29", "b29", "h29", "s29", "d29", "q29"], + v30: vreg = ["v30", "b30", "h30", "s30", "d30", "q30"], + v31: vreg = ["v31", "b31", "h31", "s31", "d31", "q31"], + z0: zreg, zreg_low16, zreg_low8 = ["z0"], + z1: zreg, zreg_low16, zreg_low8 = ["z1"], + z2: zreg, zreg_low16, zreg_low8 = ["z2"], + z3: zreg, zreg_low16, zreg_low8 = ["z3"], + z4: zreg, zreg_low16, zreg_low8 = ["z4"], + z5: zreg, zreg_low16, zreg_low8 = ["z5"], + z6: zreg, zreg_low16, zreg_low8 = ["z6"], + z7: zreg, zreg_low16, zreg_low8 = ["z7"], + z8: zreg, zreg_low16 = ["z8"], + z9: zreg, zreg_low16 = ["z9"], + z10: zreg, zreg_low16 = ["z10"], + z11: zreg, zreg_low16 = ["z11"], + z12: zreg, zreg_low16 = ["z12"], + z13: zreg, zreg_low16 = ["z13"], + z14: zreg, zreg_low16 = ["z14"], + z15: zreg, zreg_low16 = ["z15"], + z16: zreg = ["z16"], + z17: zreg = ["z17"], + z18: zreg = ["z18"], + z19: zreg = ["z19"], + z20: zreg = ["z20"], + z21: zreg = ["z21"], + z22: zreg = ["z22"], + z23: zreg = ["z23"], + z24: zreg = ["z24"], + z25: zreg = ["z25"], + z26: zreg = ["z26"], + z27: zreg = ["z27"], + z28: zreg = ["z28"], + z29: zreg = ["z29"], + z30: zreg = ["z30"], + z31: zreg = ["z31"], + p0: preg, preg_low8 = ["p0"], + p1: preg, preg_low8 = ["p1"], + p2: preg, preg_low8 = ["p2"], + p3: preg, preg_low8 = ["p3"], + p4: preg, preg_low8 = ["p4"], + p5: preg, preg_low8 = ["p5"], + p6: preg, preg_low8 = ["p6"], + p7: preg, preg_low8 = ["p7"], p8: preg = ["p8"], p9: preg = ["p9"], p10: preg = ["p10"], @@ -170,7 +235,7 @@ def_regs! { p13: preg = ["p13"], p14: preg = ["p14"], p15: preg = ["p15"], - ffr: preg = ["ffr"], + ffr: ffr_reg = ["ffr"], #error = ["x19", "w19"] => "x19 is used internally by LLVM and cannot be used as an operand for inline asm", #error = ["x29", "w29", "fp", "wfp"] => @@ -183,18 +248,55 @@ def_regs! { } impl AArch64InlineAsmReg { + fn index(self, min: u32, max: u32) -> Option { + if ((self as u32) >= min) && ((self as u32) <= max) { + Some(self as u32 - min) + } else { + None + } + } + fn x_index(self) -> Option { + self.index(Self::x0 as u32, Self::x30 as u32) + } + fn v_index(self) -> Option { + self.index(Self::v0 as u32, Self::v31 as u32) + } + fn z_index(self) -> Option { + self.index(Self::z0 as u32, Self::z31 as u32) + } + fn p_index(self) -> Option { + self.index(Self::p0 as u32, Self::p15 as u32) + } + pub fn emit( self, out: &mut dyn fmt::Write, _arch: InlineAsmArch, modifier: Option, ) -> fmt::Result { - let (prefix, index) = if (self as u32) < Self::v0 as u32 { - (modifier.unwrap_or('x'), self as u32 - Self::x0 as u32) + let (prefix, index) = if let Some(x) = self.x_index() { + (modifier.unwrap_or('x'), x) + } else if let Some(v) = self.v_index() { + (modifier.unwrap_or('v'), v) + } else if let Some(z) = self.z_index() { + (modifier.unwrap_or('z'), z) } else { - (modifier.unwrap_or('v'), self as u32 - Self::v0 as u32) + let p = self.p_index(); + assert!(p.is_some()); + (modifier.unwrap_or('p'), p.unwrap()) }; assert!(index < 32); write!(out, "{prefix}{index}") } + + pub fn overlapping_regs(self, mut cb: impl FnMut(AArch64InlineAsmReg)) { + cb(self); + if (self as u32) >= Self::v0 as u32 && (self as u32) < Self::z0 as u32 { + let index = (self as usize) - Self::v0 as usize; + cb(AArch64InlineAsmReg::parse(format!("z{}", index).as_str()).unwrap()); + } else if (self as u32) >= Self::z0 as u32 && (self as u32) < Self::p0 as u32 { + let index = (self as usize) - Self::z0 as usize; + cb(AArch64InlineAsmReg::parse(format!("v{}", index).as_str()).unwrap()); + }; + } } diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index a11884bea268f..139af26dd0308 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -415,7 +415,7 @@ impl InlineAsmReg { match self { Self::X86(r) => r.overlapping_regs(|r| cb(Self::X86(r))), Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))), - Self::AArch64(_) => cb(self), + Self::AArch64(r) => r.overlapping_regs(|r| cb(Self::AArch64(r))), Self::RiscV(_) => cb(self), Self::PowerPC(r) => r.overlapping_regs(|r| cb(Self::PowerPC(r))), Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))), @@ -702,6 +702,7 @@ pub enum InlineAsmType { VecI128(u64), VecF32(u64), VecF64(u64), + VecBool(u64), } impl InlineAsmType { @@ -725,6 +726,7 @@ impl InlineAsmType { Self::VecI128(n) => n * 16, Self::VecF32(n) => n * 4, Self::VecF64(n) => n * 8, + Self::VecBool(n) => n * 1, }) } } @@ -739,6 +741,14 @@ impl fmt::Display for InlineAsmType { Self::I128 => f.write_str("i128"), Self::F32 => f.write_str("f32"), Self::F64 => f.write_str("f64"), + Self::VecI8(n) if n == 0 => write!(f, "i8x16xN"), + Self::VecI16(n) if n == 0 => write!(f, "i16x8xN"), + Self::VecI32(n) if n == 0 => write!(f, "i32x4xN"), + Self::VecI64(n) if n == 0 => write!(f, "i64x2xN"), + Self::VecI128(n) if n == 0 => write!(f, "i128x1xN"), + Self::VecF32(n) if n == 0 => write!(f, "f32x4xN"), + Self::VecF64(n) if n == 0 => write!(f, "f64x2xN"), + Self::VecBool(n) if n == 0 => write!(f, "boolx16xN"), Self::VecI8(n) => write!(f, "i8x{n}"), Self::VecI16(n) => write!(f, "i16x{n}"), Self::VecI32(n) => write!(f, "i32x{n}"), @@ -746,6 +756,7 @@ impl fmt::Display for InlineAsmType { Self::VecI128(n) => write!(f, "i128x{n}"), Self::VecF32(n) => write!(f, "f32x{n}"), Self::VecF64(n) => write!(f, "f64x{n}"), + Self::VecBool(n) => write!(f, "boolx{n}"), } } } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 826c69ee7160b..b857520d1125d 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -406,6 +406,10 @@ fn layout_of_uncached<'tcx>( }; (*e_ty, *count, true) + } else if let ty::Slice(e_ty) = f0_ty.kind() + && def.repr().scalable() + { + (*e_ty, 1, false) } else { // First ADT field is not an array: (f0_ty, def.non_enum_variant().fields.len() as _, false) @@ -445,10 +449,19 @@ fn layout_of_uncached<'tcx>( FieldsShape::Array { stride: e_ly.size, count: e_len } }; + let abi = if def.repr().scalable() { + if let Some(elt) = def.repr().scalable { + Abi::ScalableVector { element: e_abi, elt: elt as u64 } + } else { + bug!("scalable SIMD type `{}` doesn't contain the number of elements", ty,) + } + } else { + Abi::Vector { element: e_abi, count: e_len } + }; tcx.mk_layout(LayoutS { variants: Variants::Single { index: FIRST_VARIANT }, fields, - abi: Abi::Vector { element: e_abi, count: e_len }, + abi, largest_niche: e_ly.largest_niche, size, align, @@ -480,6 +493,12 @@ fn layout_of_uncached<'tcx>( return Err(error(cx, LayoutError::Unknown(ty))); } + if def.repr().scalable() + && variants[FIRST_VARIANT].iter().all(|field| !field.0.is_zst()) + { + bug!("Fields for a Scalable vector should be a ZST"); + } + return Ok(tcx.mk_layout( cx.layout_of_union(&def.repr(), &variants) .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?, diff --git a/compiler/rustc_ty_utils/src/layout_sanity_check.rs b/compiler/rustc_ty_utils/src/layout_sanity_check.rs index 6332c614a90bb..75517cb904cf6 100644 --- a/compiler/rustc_ty_utils/src/layout_sanity_check.rs +++ b/compiler/rustc_ty_utils/src/layout_sanity_check.rs @@ -77,7 +77,7 @@ pub(super) fn sanity_check_layout<'tcx>( let Some((align, size)) = align.zip(size) else { assert_matches!( layout.layout.abi(), - Abi::Uninhabited | Abi::Aggregate { .. }, + Abi::Uninhabited | Abi::Aggregate { .. } | Abi::ScalableVector { .. }, "ABI unexpectedly missing alignment and/or size in {layout:#?}" ); return; @@ -241,7 +241,7 @@ pub(super) fn sanity_check_layout<'tcx>( assert!(align >= element.align(cx).abi); // just sanity-checking `vector_align`. // FIXME: Do some kind of check of the inner type, like for Scalar and ScalarPair. } - Abi::Uninhabited | Abi::Aggregate { .. } => {} // Nothing to check. + Abi::Uninhabited | Abi::Aggregate { .. } | Abi::ScalableVector { .. } => {} // Nothing to check. } } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 921a0fb6a9f83..2cbc2d4ccd228 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -63,6 +63,7 @@ // rustc itself never sets the feature, so this line has no effect there. #![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] #![stable(feature = "core", since = "1.6.0")] +#![cfg_attr(not(bootstrap), feature(repr_scalable))] #![doc( html_playground_url = "https://play.rust-lang.org/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", diff --git a/tests/assembly/asm/aarch64-modifiers.rs b/tests/assembly/asm/aarch64-modifiers.rs index 5196aa9fa1759..6468b86bb569d 100644 --- a/tests/assembly/asm/aarch64-modifiers.rs +++ b/tests/assembly/asm/aarch64-modifiers.rs @@ -1,9 +1,9 @@ // assembly-output: emit-asm // compile-flags: -O -// compile-flags: --target aarch64-unknown-linux-gnu +// compile-flags: --target aarch64-unknown-linux-gnu -C target-feature=+sve // needs-llvm-components: aarch64 -#![feature(no_core, lang_items, rustc_attrs)] +#![feature(no_core, lang_items, rustc_attrs, repr_simd, repr_scalable, unsized_locals, unsized_fn_params)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register)] @@ -24,6 +24,30 @@ trait Copy {} impl Copy for i32 {} +macro_rules! impl_sve_type { + ($(($v:vis, $elem_type:ty, $name:ident, $elt:literal))*) => ($( + #[repr(simd, scalable($elt))] + #[allow(non_camel_case_types)] + $v struct $name { + _ty: [$elem_type], + } + )*) +} + +impl_sve_type! { + (pub, bool, svbool_t, 16) + (pub, i8, svint8_t, 16) + (pub, u8, svuint8_t, 16) + (pub, i16, svint16_t, 8) + (pub, u16, svuint16_t, 8) + (pub, f32, svfloat32_t, 4) + (pub, i32, svint32_t, 4) + (pub, u32, svuint32_t, 4) + (pub, f64, svfloat64_t, 2) + (pub, i64, svint64_t, 2) + (pub, u64, svuint64_t, 2) +} + macro_rules! check { ($func:ident $reg:ident $code:literal) => { // -O and extern "C" guarantee that the selected register is always r0/s0/d0/q0 @@ -42,6 +66,25 @@ macro_rules! check { }; } +macro_rules! check_sve { + ($func:ident $reg:ident $code:literal) => { + // -O and extern "C" guarantee that the selected register is always r0/s0/d0/q0 + #[no_mangle] + #[target_feature(enable = "sve")] + pub unsafe extern "C" fn $func() -> svint32_t { + // Hack to avoid function merging + extern "Rust" { + fn dont_merge(s: &str); + } + dont_merge(stringify!($func)); + + let y; + asm!($code, out($reg) y); + y + } + }; +} + // CHECK-LABEL: reg: // CHECK: //APP // CHECK: mov x0, x0 @@ -143,3 +186,69 @@ check!(vreg_low16_q vreg_low16 "ldr {:q}, [x0]"); // CHECK: add v0.4s, v0.4s, v0.4s // CHECK: //NO_APP check!(vreg_low16_v vreg_low16 "add {0:v}.4s, {0:v}.4s, {0:v}.4s"); + +// CHECK-LABEL: zreg: +// CHECK: //APP +// CHECK: add z0.s, z0.s, z0.s +// CHECK: //NO_APP +check_sve!(zreg zreg "add {0}.s, {0}.s, {0}.s"); + +// CHECK-LABEL: zreg_z: +// CHECK: //APP +// CHECK: add z0.s, z0.s, z0.s +// CHECK: //NO_APP +check_sve!(zreg_z zreg "add {0:z}.s, {0:z}.s, {0:z}.s"); + +// CHECK-LABEL: zreg_b: +// CHECK: //APP +// CHECK: ldr b0, [x0] +// CHECK: //NO_APP +check!(zreg_b zreg "ldr {:b}, [x0]"); + +// CHECK-LABEL: zreg_h: +// CHECK: //APP +// CHECK: ldr h0, [x0] +// CHECK: //NO_APP +check!(zreg_h zreg "ldr {:h}, [x0]"); + +// CHECK-LABEL: zreg_s: +// CHECK: //APP +// CHECK: ldr s0, [x0] +// CHECK: //NO_APP +check!(zreg_s zreg "ldr {:s}, [x0]"); + +// CHECK-LABEL: zreg_d: +// CHECK: //APP +// CHECK: ldr d0, [x0] +// CHECK: //NO_APP +check!(zreg_d zreg "ldr {:d}, [x0]"); + +// CHECK-LABEL: zreg_q: +// CHECK: //APP +// CHECK: ldr q0, [x0] +// CHECK: //NO_APP +check!(zreg_q zreg "ldr {:q}, [x0]"); + +// CHECK-LABEL: zreg_low16: +// CHECK: //APP +// CHECK: add z0.s, z0.s, z0.s +// CHECK: //NO_APP +check_sve!(zreg_low16 zreg_low16 "add {0}.s, {0}.s, {0}.s"); + +// CHECK-LABEL: zreg_low16_z: +// CHECK: //APP +// CHECK: add z0.s, z0.s, z0.s +// CHECK: //NO_APP +check_sve!(zreg_low16_z zreg "add {0:z}.s, {0:z}.s, {0:z}.s"); + +// CHECK-LABEL: zreg_low8: +// CHECK: //APP +// CHECK: add z0.s, z0.s, z0.s +// CHECK: //NO_APP +check_sve!(zreg_low8 zreg_low8 "add {0}.s, {0}.s, {0}.s"); + +// CHECK-LABEL: zreg_low8_z: +// CHECK: //APP +// CHECK: add z0.s, z0.s, z0.s +// CHECK: //NO_APP +check_sve!(zreg_low8_z zreg_low8 "add {0:z}.s, {0:z}.s, {0:z}.s"); diff --git a/tests/assembly/asm/aarch64-types.rs b/tests/assembly/asm/aarch64-types.rs index 66c39a48c6e1d..f35d65225ec99 100644 --- a/tests/assembly/asm/aarch64-types.rs +++ b/tests/assembly/asm/aarch64-types.rs @@ -1,8 +1,8 @@ // assembly-output: emit-asm -// compile-flags: --target aarch64-unknown-linux-gnu +// compile-flags: --target aarch64-unknown-linux-gnu -C target-feature=+sve // needs-llvm-components: aarch64 -#![feature(no_core, lang_items, rustc_attrs, repr_simd)] +#![feature(no_core, lang_items, rustc_attrs, repr_simd, repr_scalable, unsized_locals, unsized_fn_params)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register, non_camel_case_types)] @@ -72,6 +72,30 @@ impl Copy for i64x2 {} impl Copy for f32x4 {} impl Copy for f64x2 {} +macro_rules! impl_sve_type { + ($(($v:vis, $elem_type:ty, $name:ident, $elt:literal))*) => ($( + #[repr(simd, scalable($elt))] + #[allow(non_camel_case_types)] + $v struct $name { + _ty: [$elem_type], + } + )*) +} + +impl_sve_type! { + (pub, bool, svbool_t, 16) + (pub, i8, svint8_t, 16) + (pub, u8, svuint8_t, 16) + (pub, i16, svint16_t, 8) + (pub, u16, svuint16_t, 8) + (pub, f32, svfloat32_t, 4) + (pub, i32, svint32_t, 4) + (pub, u32, svuint32_t, 4) + (pub, f64, svfloat64_t, 2) + (pub, i64, svint64_t, 2) + (pub, u64, svuint64_t, 2) +} + extern "C" { fn extern_func(); static extern_static: u8; @@ -107,8 +131,9 @@ pub unsafe fn issue_75761() { } macro_rules! check { - ($func:ident $ty:ident $class:ident $mov:literal $modifier:literal) => { + ($func:ident $ty:ident $class:ident $mov:literal $modifier:literal $($reg_suffix:literal)?) => { #[no_mangle] + #[target_feature(enable = "sve")] pub unsafe fn $func(x: $ty) -> $ty { // Hack to avoid function merging extern "Rust" { @@ -118,7 +143,8 @@ macro_rules! check { let y; asm!( - concat!($mov, " {:", $modifier, "}, {:", $modifier, "}"), + concat!($mov, " {:", $modifier, "}" $(, $reg_suffix)?, + ", {:", $modifier, "}" $(, $reg_suffix)?), out($class) y, in($class) x ); @@ -128,8 +154,9 @@ macro_rules! check { } macro_rules! check_reg { - ($func:ident $ty:ident $reg:tt $mov:literal) => { + ($func:ident $ty:ident $reg:tt $mov:literal $($reg_suffix:literal)?) => { #[no_mangle] + #[target_feature(enable = "sve")] pub unsafe fn $func(x: $ty) -> $ty { // Hack to avoid function merging extern "Rust" { @@ -138,7 +165,10 @@ macro_rules! check_reg { dont_merge(stringify!($func)); let y; - asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + asm!( + concat!($mov, " ", $reg $(, $reg_suffix)?, ", ", $reg $(, $reg_suffix)?), + lateout($reg) y, + in($reg) x); y } }; @@ -300,6 +330,150 @@ check!(vreg_f32x4 f32x4 vreg "fmov" "s"); // CHECK: //NO_APP check!(vreg_f64x2 f64x2 vreg "fmov" "s"); +// CHECK-LABEL: vreg_v_i8x8: +// CHECK: //APP +// CHECK: mov v{{[0-9]+}}.16b, v{{[0-9]+}}.16b +// CHECK: //NO_APP +check!(vreg_v_i8x8 i8x8 vreg "mov" "v" ".16b"); + +// CHECK-LABEL: vreg_v_i16x4: +// CHECK: //APP +// CHECK: mov v{{[0-9]+}}.16b, v{{[0-9]+}}.16b +// CHECK: //NO_APP +check!(vreg_v_i16x4 i16x4 vreg "mov" "v" ".16b"); + +// CHECK-LABEL: vreg_v_i32x2: +// CHECK: //APP +// CHECK: mov v{{[0-9]+}}.16b, v{{[0-9]+}}.16b +// CHECK: //NO_APP +check!(vreg_v_i32x2 i32x2 vreg "mov" "v" ".16b"); + +// CHECK-LABEL: vreg_v_i64x1: +// CHECK: //APP +// CHECK: mov v{{[0-9]+}}.16b, v{{[0-9]+}}.16b +// CHECK: //NO_APP +check!(vreg_v_i64x1 i64x1 vreg "mov" "v" ".16b"); + +// CHECK-LABEL: vreg_v_f32x2: +// CHECK: //APP +// CHECK: mov v{{[0-9]+}}.16b, v{{[0-9]+}}.16b +// CHECK: //NO_APP +check!(vreg_v_f32x2 f32x2 vreg "mov" "v" ".16b"); + +// CHECK-LABEL: vreg_v_f64x1: +// CHECK: //APP +// CHECK: mov v{{[0-9]+}}.16b, v{{[0-9]+}}.16b +// CHECK: //NO_APP +check!(vreg_v_f64x1 f64x1 vreg "mov" "v" ".16b"); + +// CHECK-LABEL: vreg_v_i8x16: +// CHECK: //APP +// CHECK: mov v{{[0-9]+}}.16b, v{{[0-9]+}}.16b +// CHECK: //NO_APP +check!(vreg_v_i8x16 i8x16 vreg "mov" "v" ".16b"); + +// CHECK-LABEL: vreg_v_i16x8: +// CHECK: //APP +// CHECK: mov v{{[0-9]+}}.16b, v{{[0-9]+}}.16b +// CHECK: //NO_APP +check!(vreg_v_i16x8 i16x8 vreg "mov" "v" ".16b"); + +// CHECK-LABEL: vreg_v_i32x4: +// CHECK: //APP +// CHECK: mov v{{[0-9]+}}.16b, v{{[0-9]+}}.16b +// CHECK: //NO_APP +check!(vreg_v_i32x4 i32x4 vreg "mov" "v" ".16b"); + +// CHECK-LABEL: vreg_v_i64x2: +// CHECK: //APP +// CHECK: mov v{{[0-9]+}}.16b, v{{[0-9]+}}.16b +// CHECK: //NO_APP +check!(vreg_v_i64x2 i64x2 vreg "mov" "v" ".16b"); + +// CHECK-LABEL: vreg_v_f32x4: +// CHECK: //APP +// CHECK: mov v{{[0-9]+}}.16b, v{{[0-9]+}}.16b +// CHECK: //NO_APP +check!(vreg_v_f32x4 f32x4 vreg "mov" "v" ".16b"); + +// CHECK-LABEL: vreg_v_f64x2: +// CHECK: //APP +// CHECK: mov v{{[0-9]+}}.16b, v{{[0-9]+}}.16b +// CHECK: //NO_APP +check!(vreg_v_f64x2 f64x2 vreg "mov" "v" ".16b"); + +// CHECK-LABEL: zreg_i16: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(zreg_i16 i16 zreg "fmov" "s"); + +// CHECK-LABEL: zreg_i32: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(zreg_i32 i32 zreg "fmov" "s"); + +// CHECK-LABEL: zreg_f32: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(zreg_f32 f32 zreg "fmov" "s"); + +// CHECK-LABEL: zreg_i64: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(zreg_i64 i64 zreg "fmov" "s"); + +// CHECK-LABEL: zreg_f64: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(zreg_f64 f64 zreg "fmov" "s"); + +// CHECK-LABEL: zreg_ptr: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(zreg_ptr ptr zreg "fmov" "s"); + +// CHECK-LABEL: zreg_svint8_t: +// CHECK: //APP +// CHECK: mov z{{[0-9]+}}.d, z{{[0-9]+}}.d +// CHECK: //NO_APP +check!(zreg_svint8_t svint8_t zreg "mov" "" ".d"); + +// CHECK-LABEL: zreg_svint16_t: +// CHECK: //APP +// CHECK: mov z{{[0-9]+}}.d, z{{[0-9]+}}.d +// CHECK: //NO_APP +check!(zreg_svint16_t svint16_t zreg "mov" "" ".d"); + +// CHECK-LABEL: zreg_svint32_t: +// CHECK: //APP +// CHECK: mov z{{[0-9]+}}.d, z{{[0-9]+}}.d +// CHECK: //NO_APP +check!(zreg_svint32_t svint32_t zreg "mov" "" ".d"); + +// CHECK-LABEL: zreg_svint64_t: +// CHECK: //APP +// CHECK: mov z{{[0-9]+}}.d, z{{[0-9]+}}.d +// CHECK: //NO_APP +check!(zreg_svint64_t svint64_t zreg "mov" "" ".d"); + +// CHECK-LABEL: zreg_svfloat32_t: +// CHECK: //APP +// CHECK: mov z{{[0-9]+}}.d, z{{[0-9]+}}.d +// CHECK: //NO_APP +check!(zreg_svfloat32_t svfloat32_t zreg "mov" "" ".d"); + +// CHECK-LABEL: zreg_svfloat64_t: +// CHECK: //APP +// CHECK: mov z{{[0-9]+}}.d, z{{[0-9]+}}.d +// CHECK: //NO_APP +check!(zreg_svfloat64_t svfloat64_t zreg "mov" "" ".d"); + // CHECK-LABEL: vreg_low16_i8: // CHECK: //APP // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} @@ -408,6 +582,156 @@ check!(vreg_low16_f32x4 f32x4 vreg_low16 "fmov" "s"); // CHECK: //NO_APP check!(vreg_low16_f64x2 f64x2 vreg_low16 "fmov" "s"); +// CHECK-LABEL: vreg_low16_v_i8x8: +// CHECK: //APP +// CHECK: mov v{{[0-9]+}}.16b, v{{[0-9]+}}.16b +// CHECK: //NO_APP +check!(vreg_low16_v_i8x8 i8x8 vreg_low16 "mov" "v" ".16b"); + +// CHECK-LABEL: vreg_low16_v_i16x4: +// CHECK: //APP +// CHECK: mov v{{[0-9]+}}.16b, v{{[0-9]+}}.16b +// CHECK: //NO_APP +check!(vreg_low16_v_i16x4 i16x4 vreg_low16 "mov" "v" ".16b"); + +// CHECK-LABEL: vreg_low16_v_i32x2: +// CHECK: //APP +// CHECK: mov v{{[0-9]+}}.16b, v{{[0-9]+}}.16b +// CHECK: //NO_APP +check!(vreg_low16_v_i32x2 i32x2 vreg_low16 "mov" "v" ".16b"); + +// CHECK-LABEL: vreg_low16_v_i64x1: +// CHECK: //APP +// CHECK: mov v{{[0-9]+}}.16b, v{{[0-9]+}}.16b +// CHECK: //NO_APP +check!(vreg_low16_v_i64x1 i64x1 vreg_low16 "mov" "v" ".16b"); + +// CHECK-LABEL: vreg_low16_v_f32x2: +// CHECK: //APP +// CHECK: mov v{{[0-9]+}}.16b, v{{[0-9]+}}.16b +// CHECK: //NO_APP +check!(vreg_low16_v_f32x2 f32x2 vreg_low16 "mov" "v" ".16b"); + +// CHECK-LABEL: vreg_low16_v_f64x1: +// CHECK: //APP +// CHECK: mov v{{[0-9]+}}.16b, v{{[0-9]+}}.16b +// CHECK: //NO_APP +check!(vreg_low16_v_f64x1 f64x1 vreg_low16 "mov" "v" ".16b"); + +// CHECK-LABEL: vreg_low16_v_i8x16: +// CHECK: //APP +// CHECK: mov v{{[0-9]+}}.16b, v{{[0-9]+}}.16b +// CHECK: //NO_APP +check!(vreg_low16_v_i8x16 i8x16 vreg_low16 "mov" "v" ".16b"); + +// CHECK-LABEL: vreg_low16_v_i16x8: +// CHECK: //APP +// CHECK: mov v{{[0-9]+}}.16b, v{{[0-9]+}}.16b +// CHECK: //NO_APP +check!(vreg_low16_v_i16x8 i16x8 vreg_low16 "mov" "v" ".16b"); + +// CHECK-LABEL: vreg_low16_v_i32x4: +// CHECK: //APP +// CHECK: mov v{{[0-9]+}}.16b, v{{[0-9]+}}.16b +// CHECK: //NO_APP +check!(vreg_low16_v_i32x4 i32x4 vreg_low16 "mov" "v" ".16b"); + +// CHECK-LABEL: vreg_low16_v_i64x2: +// CHECK: //APP +// CHECK: mov v{{[0-9]+}}.16b, v{{[0-9]+}}.16b +// CHECK: //NO_APP +check!(vreg_low16_v_i64x2 i64x2 vreg_low16 "mov" "v" ".16b"); + +// CHECK-LABEL: vreg_low16_v_f32x4: +// CHECK: //APP +// CHECK: mov v{{[0-9]+}}.16b, v{{[0-9]+}}.16b +// CHECK: //NO_APP +check!(vreg_low16_v_f32x4 f32x4 vreg_low16 "mov" "v" ".16b"); + +// CHECK-LABEL: vreg_low16_v_f64x2: +// CHECK: //APP +// CHECK: mov v{{[0-9]+}}.16b, v{{[0-9]+}}.16b +// CHECK: //NO_APP +check!(vreg_low16_v_f64x2 f64x2 vreg_low16 "mov" "v" ".16b"); + +// CHECK-LABEL: zreg_low16_svint8_t: +// CHECK: //APP +// CHECK: mov z{{[0-9]+}}.d, z{{[0-9]+}}.d +// CHECK: //NO_APP +check!(zreg_low16_svint8_t svint8_t zreg_low16 "mov" "" ".d"); + +// CHECK-LABEL: zreg_low16_svint16_t: +// CHECK: //APP +// CHECK: mov z{{[0-9]+}}.d, z{{[0-9]+}}.d +// CHECK: //NO_APP +check!(zreg_low16_svint16_t svint16_t zreg_low16 "mov" "" ".d"); + +// CHECK-LABEL: zreg_low16_svint32_t: +// CHECK: //APP +// CHECK: mov z{{[0-9]+}}.d, z{{[0-9]+}}.d +// CHECK: //NO_APP +check!(zreg_low16_svint32_t svint32_t zreg_low16 "mov" "" ".d"); + +// CHECK-LABEL: zreg_low16_svint64_t: +// CHECK: //APP +// CHECK: mov z{{[0-9]+}}.d, z{{[0-9]+}}.d +// CHECK: //NO_APP +check!(zreg_low16_svint64_t svint64_t zreg_low16 "mov" "" ".d"); + +// CHECK-LABEL: zreg_low16_svfloat32_t: +// CHECK: //APP +// CHECK: mov z{{[0-9]+}}.d, z{{[0-9]+}}.d +// CHECK: //NO_APP +check!(zreg_low16_svfloat32_t svfloat32_t zreg_low16 "mov" "" ".d"); + +// CHECK-LABEL: zreg_low16_svfloat64_t: +// CHECK: //APP +// CHECK: mov z{{[0-9]+}}.d, z{{[0-9]+}}.d +// CHECK: //NO_APP +check!(zreg_low16_svfloat64_t svfloat64_t zreg_low16 "mov" "" ".d"); + +// CHECK-LABEL: zreg_low8_svint8_t: +// CHECK: //APP +// CHECK: mov z{{[0-9]+}}.d, z{{[0-9]+}}.d +// CHECK: //NO_APP +check!(zreg_low8_svint8_t svint8_t zreg_low8 "mov" "" ".d"); + +// CHECK-LABEL: zreg_low8_svint16_t: +// CHECK: //APP +// CHECK: mov z{{[0-7]}}.d, z{{[0-7]}}.d +// CHECK: //NO_APP +check!(zreg_low8_svint16_t svint16_t zreg_low8 "mov" "" ".d"); + +// CHECK-LABEL: zreg_low8_svint32_t: +// CHECK: //APP +// CHECK: mov z{{[0-7]}}.d, z{{[0-7]}}.d +// CHECK: //NO_APP +check!(zreg_low8_svint32_t svint32_t zreg_low8 "mov" "" ".d"); + +// CHECK-LABEL: zreg_low8_svint64_t: +// CHECK: //APP +// CHECK: mov z{{[0-7]}}.d, z{{[0-7]}}.d +// CHECK: //NO_APP +check!(zreg_low8_svint64_t svint64_t zreg_low8 "mov" "" ".d"); + +// CHECK-LABEL: zreg_low8_svfloat32_t: +// CHECK: //APP +// CHECK: mov z{{[0-7]}}.d, z{{[0-7]}}.d +// CHECK: //NO_APP +check!(zreg_low8_svfloat32_t svfloat32_t zreg_low8 "mov" "" ".d"); + +// CHECK-LABEL: zreg_low8_svfloat64_t: +// CHECK: //APP +// CHECK: mov z{{[0-7]}}.d, z{{[0-7]}}.d +// CHECK: //NO_APP +check!(zreg_low8_svfloat64_t svfloat64_t zreg_low8 "mov" "" ".d"); + +// CHECK-LABEL: preg_svbool_t: +// CHECK: //APP +// CHECK: mov p{{[0-9]+}}.b, p{{[0-9]+}}.b +// CHECK: //NO_APP +check!(preg_svbool_t svbool_t preg "mov" "" ".b"); + // CHECK-LABEL: x0_i8: // CHECK: //APP // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} @@ -563,3 +887,81 @@ check_reg!(v0_f32x4 f32x4 "s0" "fmov"); // CHECK: fmov s0, s0 // CHECK: //NO_APP check_reg!(v0_f64x2 f64x2 "s0" "fmov"); + +// CHECK-LABEL: v0_v_i8x16: +// CHECK: //APP +// CHECK: mov v0.16b, v0.16b +// CHECK: //NO_APP +check_reg!(v0_v_i8x16 i8x16 "v0" "mov" ".16b"); + +// CHECK-LABEL: v0_v_i16x8: +// CHECK: //APP +// CHECK: mov v0.16b, v0.16b +// CHECK: //NO_APP +check_reg!(v0_v_i16x8 i16x8 "v0" "mov" ".16b"); + +// CHECK-LABEL: v0_v_i32x4: +// CHECK: //APP +// CHECK: mov v0.16b, v0.16b +// CHECK: //NO_APP +check_reg!(v0_v_i32x4 i32x4 "v0" "mov" ".16b"); + +// CHECK-LABEL: v0_v_i64x2: +// CHECK: //APP +// CHECK: mov v0.16b, v0.16b +// CHECK: //NO_APP +check_reg!(v0_v_i64x2 i64x2 "v0" "mov" ".16b"); + +// CHECK-LABEL: v0_v_f32x4: +// CHECK: //APP +// CHECK: mov v0.16b, v0.16b +// CHECK: //NO_APP +check_reg!(v0_v_f32x4 f32x4 "v0" "mov" ".16b"); + +// CHECK-LABEL: v0_v_f64x2: +// CHECK: //APP +// CHECK: mov v0.16b, v0.16b +// CHECK: //NO_APP +check_reg!(v0_v_f64x2 f64x2 "v0" "mov" ".16b"); + +// CHECK-LABEL: z0_svint8_t: +// CHECK: //APP +// CHECK: mov z0.d, z0.d +// CHECK: //NO_APP +check_reg!(z0_svint8_t svint8_t "z0" "mov" ".d"); + +// CHECK-LABEL: z0_svint16_t: +// CHECK: //APP +// CHECK: mov z0.d, z0.d +// CHECK: //NO_APP +check_reg!(z0_svint16_t svint16_t "z0" "mov" ".d"); + +// CHECK-LABEL: z0_svint32_t: +// CHECK: //APP +// CHECK: mov z0.d, z0.d +// CHECK: //NO_APP +check_reg!(z0_svint32_t svint32_t "z0" "mov" ".d"); + +// CHECK-LABEL: z0_svint64_t: +// CHECK: //APP +// CHECK: mov z0.d, z0.d +// CHECK: //NO_APP +check_reg!(z0_svint64_t svint64_t "z0" "mov" ".d"); + +// CHECK-LABEL: z0_svfloat32_t: +// CHECK: //APP +// CHECK: mov z0.d, z0.d +// CHECK: //NO_APP +check_reg!(z0_svfloat32_t svfloat32_t "z0" "mov" ".d"); + +// CHECK-LABEL: z0_svfloat64_t: +// CHECK: //APP +// CHECK: mov z0.d, z0.d +// CHECK: //NO_APP +check_reg!(z0_svfloat64_t svfloat64_t "z0" "mov" ".d"); + +// CHECK-LABEL: p0_svbool_t: +// CHECK: //APP +// CHECK: mov p0.b, p0.b +// CHECK: //NO_APP +check_reg!(p0_svbool_t svbool_t "p0" "mov" ".b"); diff --git a/tests/ui/asm/aarch64/bad-reg.rs b/tests/ui/asm/aarch64/bad-reg.rs index 9ccb8ed676269..cd20324a11651 100644 --- a/tests/ui/asm/aarch64/bad-reg.rs +++ b/tests/ui/asm/aarch64/bad-reg.rs @@ -1,13 +1,20 @@ // only-aarch64 -// compile-flags: -C target-feature=+neon +// compile-flags: -A incomplete-features -C target-feature=+neon,+sve -#![feature(asm_const)] +#![feature(repr_simd, stdarch_aarch64_sve, stdsimd, asm_const, unsized_locals, unsized_fn_params)] +use std::arch::aarch64::float64x2_t; +use std::arch::aarch64::sve::svfloat64_t; +use std::arch::aarch64::sve::svdup_n_f64; use std::arch::asm; fn main() { let mut foo = 0; let mut bar = 0; + + let f64x2: float64x2_t = unsafe { std::mem::transmute(0i128) }; + let mut f64xN: svfloat64_t = svdup_n_f64(0.0); + unsafe { // Bad register/register class @@ -21,6 +28,8 @@ fn main() { //~^ ERROR invalid asm template modifier for this register class asm!("{:r}", in(vreg_low16) foo); //~^ ERROR invalid asm template modifier for this register class + asm!("{:v}", in(zreg) foo); + //~^ ERROR invalid asm template modifier for this register class asm!("{:a}", const 0); //~^ ERROR asm template modifiers are not allowed for `const` arguments asm!("{:a}", sym main); @@ -34,15 +43,20 @@ fn main() { asm!("", in("x19") foo); //~^ ERROR invalid register `x19`: x19 is used internally by LLVM and cannot be used as an operand for inline asm - asm!("", in("p0") foo); - //~^ ERROR register class `preg` can only be used as a clobber, not as an input or output + asm!("{}", in(zreg) f64x2); + //~^ ERROR type `float64x2_t` cannot be used with this register class + asm!("{}", in(vreg) f64xN); + //~^ ERROR type `svfloat64_t` cannot be used with this register class + + asm!("", in("ffr") foo); + //~^ ERROR register class `ffr_reg` can only be used as a clobber, not as an input or output //~| ERROR type `i32` cannot be used with this register class - asm!("", out("p0") _); - asm!("{}", in(preg) foo); - //~^ ERROR register class `preg` can only be used as a clobber, not as an input or output + asm!("", out("ffr") _); + asm!("{}", in(ffr_reg) foo); + //~^ ERROR register class `ffr_reg` can only be used as a clobber, not as an input or output //~| ERROR type `i32` cannot be used with this register class - asm!("{}", out(preg) _); - //~^ ERROR register class `preg` can only be used as a clobber, not as an input or output + asm!("{}", out(ffr_reg) _); + //~^ ERROR register class `ffr_reg` can only be used as a clobber, not as an input or output // Explicit register conflicts // (except in/lateout which don't conflict) @@ -57,5 +71,10 @@ fn main() { asm!("", in("v0") foo, out("q0") bar); //~^ ERROR register `v0` conflicts with register `v0` asm!("", in("v0") foo, lateout("q0") bar); + asm!("", in("v0") foo, in("z0") bar); + //~^ ERROR register `z0` conflicts with register `v0` + asm!("", in("v0") foo, out("z0") bar); + //~^ ERROR register `z0` conflicts with register `v0` + asm!("", in("v0") foo, lateout("z0") bar); } } diff --git a/tests/ui/asm/aarch64/bad-reg.stderr b/tests/ui/asm/aarch64/bad-reg.stderr index 0ba627dac309f..55c9126cbc39f 100644 --- a/tests/ui/asm/aarch64/bad-reg.stderr +++ b/tests/ui/asm/aarch64/bad-reg.stderr @@ -1,17 +1,17 @@ error: invalid register class `foo`: unknown register class - --> $DIR/bad-reg.rs:14:20 + --> $DIR/bad-reg.rs:21:20 | LL | asm!("{}", in(foo) foo); | ^^^^^^^^^^^ error: invalid register `foo`: unknown register - --> $DIR/bad-reg.rs:16:18 + --> $DIR/bad-reg.rs:23:18 | LL | asm!("", in("foo") foo); | ^^^^^^^^^^^^^ error: invalid asm template modifier for this register class - --> $DIR/bad-reg.rs:18:15 + --> $DIR/bad-reg.rs:25:15 | LL | asm!("{:z}", in(reg) foo); | ^^^^ ----------- argument @@ -21,7 +21,7 @@ LL | asm!("{:z}", in(reg) foo); = note: the `reg` register class supports the following template modifiers: `w`, `x` error: invalid asm template modifier for this register class - --> $DIR/bad-reg.rs:20:15 + --> $DIR/bad-reg.rs:27:15 | LL | asm!("{:r}", in(vreg) foo); | ^^^^ ------------ argument @@ -31,7 +31,7 @@ LL | asm!("{:r}", in(vreg) foo); = note: the `vreg` register class supports the following template modifiers: `b`, `h`, `s`, `d`, `q`, `v` error: invalid asm template modifier for this register class - --> $DIR/bad-reg.rs:22:15 + --> $DIR/bad-reg.rs:29:15 | LL | asm!("{:r}", in(vreg_low16) foo); | ^^^^ ------------------ argument @@ -40,8 +40,18 @@ LL | asm!("{:r}", in(vreg_low16) foo); | = note: the `vreg_low16` register class supports the following template modifiers: `b`, `h`, `s`, `d`, `q`, `v` +error: invalid asm template modifier for this register class + --> $DIR/bad-reg.rs:31:15 + | +LL | asm!("{:v}", in(zreg) foo); + | ^^^^ ------------ argument + | | + | template modifier + | + = note: the `zreg` register class supports the following template modifiers: `b`, `h`, `s`, `d`, `q`, `z` + error: asm template modifiers are not allowed for `const` arguments - --> $DIR/bad-reg.rs:24:15 + --> $DIR/bad-reg.rs:33:15 | LL | asm!("{:a}", const 0); | ^^^^ ------- argument @@ -49,7 +59,7 @@ LL | asm!("{:a}", const 0); | template modifier error: asm template modifiers are not allowed for `sym` arguments - --> $DIR/bad-reg.rs:26:15 + --> $DIR/bad-reg.rs:35:15 | LL | asm!("{:a}", sym main); | ^^^^ -------- argument @@ -57,49 +67,49 @@ LL | asm!("{:a}", sym main); | template modifier error: invalid register `x29`: the frame pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:28:18 + --> $DIR/bad-reg.rs:37:18 | LL | asm!("", in("x29") foo); | ^^^^^^^^^^^^^ error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:30:18 + --> $DIR/bad-reg.rs:39:18 | LL | asm!("", in("sp") foo); | ^^^^^^^^^^^^ error: invalid register `xzr`: the zero register cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:32:18 + --> $DIR/bad-reg.rs:41:18 | LL | asm!("", in("xzr") foo); | ^^^^^^^^^^^^^ error: invalid register `x19`: x19 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:34:18 + --> $DIR/bad-reg.rs:43:18 | LL | asm!("", in("x19") foo); | ^^^^^^^^^^^^^ -error: register class `preg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:37:18 +error: register class `ffr_reg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:51:18 | -LL | asm!("", in("p0") foo); - | ^^^^^^^^^^^^ +LL | asm!("", in("ffr") foo); + | ^^^^^^^^^^^^^ -error: register class `preg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:41:20 +error: register class `ffr_reg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:55:20 | -LL | asm!("{}", in(preg) foo); - | ^^^^^^^^^^^^ +LL | asm!("{}", in(ffr_reg) foo); + | ^^^^^^^^^^^^^^^ -error: register class `preg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:44:20 +error: register class `ffr_reg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:58:20 | -LL | asm!("{}", out(preg) _); - | ^^^^^^^^^^^ +LL | asm!("{}", out(ffr_reg) _); + | ^^^^^^^^^^^^^^ error: register `x0` conflicts with register `x0` - --> $DIR/bad-reg.rs:50:32 + --> $DIR/bad-reg.rs:64:32 | LL | asm!("", in("x0") foo, in("w0") bar); | ------------ ^^^^^^^^^^^^ register `x0` @@ -107,7 +117,7 @@ LL | asm!("", in("x0") foo, in("w0") bar); | register `x0` error: register `x0` conflicts with register `x0` - --> $DIR/bad-reg.rs:52:32 + --> $DIR/bad-reg.rs:66:32 | LL | asm!("", in("x0") foo, out("x0") bar); | ------------ ^^^^^^^^^^^^^ register `x0` @@ -115,13 +125,13 @@ LL | asm!("", in("x0") foo, out("x0") bar); | register `x0` | help: use `lateout` instead of `out` to avoid conflict - --> $DIR/bad-reg.rs:52:18 + --> $DIR/bad-reg.rs:66:18 | LL | asm!("", in("x0") foo, out("x0") bar); | ^^^^^^^^^^^^ error: register `v0` conflicts with register `v0` - --> $DIR/bad-reg.rs:55:32 + --> $DIR/bad-reg.rs:69:32 | LL | asm!("", in("v0") foo, in("q0") bar); | ------------ ^^^^^^^^^^^^ register `v0` @@ -129,7 +139,7 @@ LL | asm!("", in("v0") foo, in("q0") bar); | register `v0` error: register `v0` conflicts with register `v0` - --> $DIR/bad-reg.rs:57:32 + --> $DIR/bad-reg.rs:71:32 | LL | asm!("", in("v0") foo, out("q0") bar); | ------------ ^^^^^^^^^^^^^ register `v0` @@ -137,26 +147,66 @@ LL | asm!("", in("v0") foo, out("q0") bar); | register `v0` | help: use `lateout` instead of `out` to avoid conflict - --> $DIR/bad-reg.rs:57:18 + --> $DIR/bad-reg.rs:71:18 | LL | asm!("", in("v0") foo, out("q0") bar); | ^^^^^^^^^^^^ +error: register `z0` conflicts with register `v0` + --> $DIR/bad-reg.rs:74:32 + | +LL | asm!("", in("v0") foo, in("z0") bar); + | ------------ ^^^^^^^^^^^^ register `z0` + | | + | register `v0` + +error: register `z0` conflicts with register `v0` + --> $DIR/bad-reg.rs:76:32 + | +LL | asm!("", in("v0") foo, out("z0") bar); + | ------------ ^^^^^^^^^^^^^ register `z0` + | | + | register `v0` + | +help: use `lateout` instead of `out` to avoid conflict + --> $DIR/bad-reg.rs:76:18 + | +LL | asm!("", in("v0") foo, out("z0") bar); + | ^^^^^^^^^^^^ + +error: type `float64x2_t` cannot be used with this register class + --> $DIR/bad-reg.rs:46:29 + | +LL | asm!("{}", in(zreg) f64x2); + | ^^^^^ + | + = note: register class `zreg` supports these types: i16, i32, i64, f32, f64, i8x16xN, i16x8xN, i32x4xN, i64x2xN, f32x4xN, f64x2xN + = help: consider using the `vreg` register class instead + +error: type `svfloat64_t` cannot be used with this register class + --> $DIR/bad-reg.rs:48:29 + | +LL | asm!("{}", in(vreg) f64xN); + | ^^^^^ + | + = note: register class `vreg` supports these types: i8, i16, i32, i64, f32, f64, i8x8, i16x4, i32x2, i64x1, f32x2, f64x1, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2 + = help: consider using the `zreg` register class instead + error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:37:27 + --> $DIR/bad-reg.rs:51:28 | -LL | asm!("", in("p0") foo); - | ^^^ +LL | asm!("", in("ffr") foo); + | ^^^ | - = note: register class `preg` supports these types: + = note: register class `ffr_reg` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:41:29 + --> $DIR/bad-reg.rs:55:32 | -LL | asm!("{}", in(preg) foo); - | ^^^ +LL | asm!("{}", in(ffr_reg) foo); + | ^^^ | - = note: register class `preg` supports these types: + = note: register class `ffr_reg` supports these types: -error: aborting due to 20 previous errors +error: aborting due to 25 previous errors diff --git a/tests/ui/asm/aarch64/type-check-3.rs b/tests/ui/asm/aarch64/type-check-3.rs index 623f6593d79ba..7c686bf0a3b2f 100644 --- a/tests/ui/asm/aarch64/type-check-3.rs +++ b/tests/ui/asm/aarch64/type-check-3.rs @@ -1,9 +1,11 @@ // only-aarch64 -// compile-flags: -C target-feature=+neon +// compile-flags: -A incomplete-features -C target-feature=+neon,+sve -#![feature(repr_simd, stdsimd, asm_const)] +#![feature(repr_simd, stdarch_aarch64_sve, stdsimd, asm_const, unsized_locals, unsized_fn_params)] use std::arch::aarch64::float64x2_t; +use std::arch::aarch64::sve::svfloat64_t; +use std::arch::aarch64::sve::svdup_n_f64; use std::arch::{asm, global_asm}; #[repr(simd)] @@ -13,6 +15,7 @@ struct Simd256bit(f64, f64, f64, f64); fn main() { let f64x2: float64x2_t = unsafe { std::mem::transmute(0i128) }; let f64x4 = Simd256bit(0.0, 0.0, 0.0, 0.0); + let f64xN: svfloat64_t = svdup_n_f64(0.0); unsafe { // Types must be listed in the register class. @@ -34,13 +37,24 @@ fn main() { asm!("{:q}", in(vreg) f64x2); asm!("{:v}", in(vreg) f64x2); + asm!("{:h}", in(zreg) 0u16); + asm!("{:s}", in(zreg) 0u32); + asm!("{:s}", in(zreg) 0f32); + asm!("{:d}", in(zreg) 0u64); + asm!("{:d}", in(zreg) 0f64); + asm!("{:q}", in(zreg) f64xN); + asm!("{:z}", in(zreg) f64xN); + // Should be the same as vreg asm!("{:q}", in(vreg_low16) f64x2); + asm!("{}", in(zreg_low8) f64xN); + asm!("{}", in(zreg_low16) f64xN); // Template modifiers of a different size to the argument are fine asm!("{:w}", in(reg) 0u64); asm!("{:x}", in(reg) 0u32); asm!("{:b}", in(vreg) 0u64); + asm!("{:b}", in(zreg) 0u64); asm!("{:d}", in(vreg_low16) f64x2); // Template modifier suggestions for sub-registers @@ -63,6 +77,13 @@ fn main() { asm!("{}", in(vreg_low16) 0f64); //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(zreg) 0i16); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(zreg) 0f32); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(zreg) 0f64); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{0} {0}", in(reg) 0i16); //~^ WARN formatting may not be suitable for sub-register argument asm!("{0} {0:x}", in(reg) 0i16); diff --git a/tests/ui/asm/aarch64/type-check-3.stderr b/tests/ui/asm/aarch64/type-check-3.stderr index f710df2dcde96..dc7784088438b 100644 --- a/tests/ui/asm/aarch64/type-check-3.stderr +++ b/tests/ui/asm/aarch64/type-check-3.stderr @@ -1,5 +1,5 @@ warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:48:15 + --> $DIR/type-check-3.rs:62:15 | LL | asm!("{}", in(reg) 0u8); | ^^ --- for this argument @@ -9,7 +9,7 @@ LL | asm!("{}", in(reg) 0u8); = note: `#[warn(asm_sub_register)]` on by default warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:50:15 + --> $DIR/type-check-3.rs:64:15 | LL | asm!("{}", in(reg) 0u16); | ^^ ---- for this argument @@ -18,7 +18,7 @@ LL | asm!("{}", in(reg) 0u16); = help: or use `{0:x}` to keep the default formatting of `x0` warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:52:15 + --> $DIR/type-check-3.rs:66:15 | LL | asm!("{}", in(reg) 0i32); | ^^ ---- for this argument @@ -27,7 +27,7 @@ LL | asm!("{}", in(reg) 0i32); = help: or use `{0:x}` to keep the default formatting of `x0` warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:54:15 + --> $DIR/type-check-3.rs:68:15 | LL | asm!("{}", in(reg) 0f32); | ^^ ---- for this argument @@ -36,7 +36,7 @@ LL | asm!("{}", in(reg) 0f32); = help: or use `{0:x}` to keep the default formatting of `x0` warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:57:15 + --> $DIR/type-check-3.rs:71:15 | LL | asm!("{}", in(vreg) 0i16); | ^^ ---- for this argument @@ -45,7 +45,7 @@ LL | asm!("{}", in(vreg) 0i16); = help: or use `{0:v}` to keep the default formatting of `v0` warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:59:15 + --> $DIR/type-check-3.rs:73:15 | LL | asm!("{}", in(vreg) 0f32); | ^^ ---- for this argument @@ -54,7 +54,7 @@ LL | asm!("{}", in(vreg) 0f32); = help: or use `{0:v}` to keep the default formatting of `v0` warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:61:15 + --> $DIR/type-check-3.rs:75:15 | LL | asm!("{}", in(vreg) 0f64); | ^^ ---- for this argument @@ -63,7 +63,7 @@ LL | asm!("{}", in(vreg) 0f64); = help: or use `{0:v}` to keep the default formatting of `v0` warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:63:15 + --> $DIR/type-check-3.rs:77:15 | LL | asm!("{}", in(vreg_low16) 0f64); | ^^ ---- for this argument @@ -72,7 +72,34 @@ LL | asm!("{}", in(vreg_low16) 0f64); = help: or use `{0:v}` to keep the default formatting of `v0` warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:66:15 + --> $DIR/type-check-3.rs:80:15 + | +LL | asm!("{}", in(zreg) 0i16); + | ^^ ---- for this argument + | + = help: use `{0:h}` to have the register formatted as `h0` + = help: or use `{0:z}` to keep the default formatting of `z0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:82:15 + | +LL | asm!("{}", in(zreg) 0f32); + | ^^ ---- for this argument + | + = help: use `{0:s}` to have the register formatted as `s0` + = help: or use `{0:z}` to keep the default formatting of `z0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:84:15 + | +LL | asm!("{}", in(zreg) 0f64); + | ^^ ---- for this argument + | + = help: use `{0:d}` to have the register formatted as `d0` + = help: or use `{0:z}` to keep the default formatting of `z0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:87:15 | LL | asm!("{0} {0}", in(reg) 0i16); | ^^^ ^^^ ---- for this argument @@ -81,7 +108,7 @@ LL | asm!("{0} {0}", in(reg) 0i16); = help: or use `{0:x}` to keep the default formatting of `x0` warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:68:15 + --> $DIR/type-check-3.rs:89:15 | LL | asm!("{0} {0:x}", in(reg) 0i16); | ^^^ ---- for this argument @@ -90,7 +117,7 @@ LL | asm!("{0} {0:x}", in(reg) 0i16); = help: or use `{0:x}` to keep the default formatting of `x0` error: type `i128` cannot be used with this register class - --> $DIR/type-check-3.rs:73:28 + --> $DIR/type-check-3.rs:94:28 | LL | asm!("{}", in(reg) 0i128); | ^^^^^ @@ -98,7 +125,7 @@ LL | asm!("{}", in(reg) 0i128); = note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64 error: type `float64x2_t` cannot be used with this register class - --> $DIR/type-check-3.rs:75:28 + --> $DIR/type-check-3.rs:96:28 | LL | asm!("{}", in(reg) f64x2); | ^^^^^ @@ -106,7 +133,7 @@ LL | asm!("{}", in(reg) f64x2); = note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64 error: type `Simd256bit` cannot be used with this register class - --> $DIR/type-check-3.rs:77:29 + --> $DIR/type-check-3.rs:98:29 | LL | asm!("{}", in(vreg) f64x4); | ^^^^^ @@ -114,7 +141,7 @@ LL | asm!("{}", in(vreg) f64x4); = note: register class `vreg` supports these types: i8, i16, i32, i64, f32, f64, i8x8, i16x4, i32x2, i64x1, f32x2, f64x1, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2 error: incompatible types for asm inout argument - --> $DIR/type-check-3.rs:88:33 + --> $DIR/type-check-3.rs:109:33 | LL | asm!("{:x}", inout(reg) 0u32 => val_f32); | ^^^^ ^^^^^^^ type `f32` @@ -124,7 +151,7 @@ LL | asm!("{:x}", inout(reg) 0u32 => val_f32); = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size error: incompatible types for asm inout argument - --> $DIR/type-check-3.rs:90:33 + --> $DIR/type-check-3.rs:111:33 | LL | asm!("{:x}", inout(reg) 0u32 => val_ptr); | ^^^^ ^^^^^^^ type `*mut u8` @@ -134,7 +161,7 @@ LL | asm!("{:x}", inout(reg) 0u32 => val_ptr); = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size error: incompatible types for asm inout argument - --> $DIR/type-check-3.rs:92:33 + --> $DIR/type-check-3.rs:113:33 | LL | asm!("{:x}", inout(reg) main => val_u32); | ^^^^ ^^^^^^^ type `u32` @@ -143,5 +170,5 @@ LL | asm!("{:x}", inout(reg) main => val_u32); | = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size -error: aborting due to 6 previous errors; 10 warnings emitted +error: aborting due to 6 previous errors; 13 warnings emitted 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..ef1b53393583b --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-repr-scalable.rs @@ -0,0 +1,8 @@ +#![feature(repr_simd)] + +#[repr(simd, scalable(16))] //~ error: Scalable SIMD types are experimental +struct Foo { + _ty: [i8; 0], +} + +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..c7df9f97aa147 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-repr-scalable.stderr @@ -0,0 +1,11 @@ +error[E0658]: Scalable SIMD types are experimental and possibly buggy + --> $DIR/feature-gate-repr-scalable.rs:3:1 + | +LL | #[repr(simd, scalable(16))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(repr_scalable)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout index 3fc130f01765a..b90e4e37bbe12 100644 --- a/tests/ui/thir-print/thir-tree-match.stdout +++ b/tests/ui/thir-print/thir-tree-match.stdout @@ -105,7 +105,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])) }], flags: NO_VARIANT_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: [], flags: NO_VARIANT_FLAGS }] flags: IS_ENUM - repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 3477539199540094892 } + repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), scalable: None, field_shuffle_seed: 3477539199540094892 } args: [] variant_index: 0 subpatterns: [ @@ -119,7 +119,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: [], flags: NO_VARIANT_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: [], flags: NO_VARIANT_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: [], flags: NO_VARIANT_FLAGS }] flags: IS_ENUM - repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 10333377570083945360 } + repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), scalable: None, field_shuffle_seed: 10333377570083945360 } args: [] variant_index: 0 subpatterns: [] @@ -178,7 +178,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])) }], flags: NO_VARIANT_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: [], flags: NO_VARIANT_FLAGS }] flags: IS_ENUM - repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 3477539199540094892 } + repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), scalable: None, field_shuffle_seed: 3477539199540094892 } args: [] variant_index: 0 subpatterns: [ @@ -241,7 +241,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])) }], flags: NO_VARIANT_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: [], flags: NO_VARIANT_FLAGS }] flags: IS_ENUM - repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 3477539199540094892 } + repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), scalable: None, field_shuffle_seed: 3477539199540094892 } args: [] variant_index: 1 subpatterns: []