From 4c14a6d4dc946d797046de4fd6d4f942cd22825e Mon Sep 17 00:00:00 2001 From: Jamie Cunliffe Date: Tue, 15 Aug 2023 15:17:29 +0100 Subject: [PATCH 1/3] Prototype of scalable vectors The representation of the element type has been changed to be a slice rather than a zero length array. Two feature gates are now required in core_arch unsized fn params and unsized locals. This still leaves unsized return types being an issue. For this we are currently bypassing some of the `Sized` trait checking to pass when the type is scalable simd. This still leaves the copy issue. For that we have marked scalable simd types as trivally pure clone copy. We have still had to remove some trait checks for the copy trait with this though as they are still performed in certain situations. The implementation of `transmute` is also an issue for us. For this a new SIMD intrinsic has been created simd_reinterpret which performs a transmute on SIMD vectors. A few intrinsics need to be able to produce an LLVM `undef` this intrinsic will also produce that when given a zero sized input. --- compiler/rustc_abi/src/layout.rs | 3 +- compiler/rustc_abi/src/lib.rs | 26 ++++++++++++++-- compiler/rustc_attr/messages.ftl | 3 ++ compiler/rustc_attr/src/builtin.rs | 27 ++++++++++++++++- .../rustc_attr/src/session_diagnostics.rs | 8 +++++ compiler/rustc_borrowck/src/type_check/mod.rs | 22 ++++++++++---- compiler/rustc_codegen_gcc/src/abi.rs | 1 + .../rustc_codegen_gcc/src/intrinsic/mod.rs | 2 +- compiler/rustc_codegen_gcc/src/type_of.rs | 5 ++-- compiler/rustc_codegen_llvm/src/abi.rs | 1 + compiler/rustc_codegen_llvm/src/builder.rs | 5 +++- .../src/debuginfo/metadata.rs | 1 + compiler/rustc_codegen_llvm/src/intrinsic.rs | 30 +++++++++++++++++-- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 + compiler/rustc_codegen_llvm/src/type_.rs | 4 +++ compiler/rustc_codegen_llvm/src/type_of.rs | 17 +++++++++-- compiler/rustc_codegen_ssa/messages.ftl | 1 + compiler/rustc_codegen_ssa/src/errors.rs | 8 +++++ .../rustc_codegen_ssa/src/mir/debuginfo.rs | 5 ++++ compiler/rustc_codegen_ssa/src/mir/operand.rs | 5 +++- compiler/rustc_codegen_ssa/src/mir/place.rs | 9 ++++-- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 1 + .../src/interpret/validity.rs | 2 +- .../src/util/check_validity_requirement.rs | 1 + compiler/rustc_error_codes/src/error_codes.rs | 1 + .../src/error_codes/E0796.md | 10 +++++++ .../rustc_hir_analysis/src/check/check.rs | 9 +++--- .../rustc_hir_analysis/src/check/intrinsic.rs | 1 + compiler/rustc_hir_typeck/src/check.rs | 9 +++++- compiler/rustc_hir_typeck/src/expr.rs | 7 ++++- compiler/rustc_hir_typeck/src/lib.rs | 5 +++- compiler/rustc_middle/src/ty/mod.rs | 14 ++++++++- compiler/rustc_middle/src/ty/sty.rs | 18 +++++++++++ .../src/build/expr/as_operand.rs | 6 ++-- compiler/rustc_passes/src/check_attr.rs | 3 ++ compiler/rustc_span/src/symbol.rs | 3 ++ compiler/rustc_target/src/abi/call/aarch64.rs | 1 + compiler/rustc_target/src/abi/call/arm.rs | 1 + .../rustc_target/src/abi/call/loongarch.rs | 4 ++- compiler/rustc_target/src/abi/call/mod.rs | 12 +++++++- .../rustc_target/src/abi/call/powerpc64.rs | 1 + compiler/rustc_target/src/abi/call/riscv.rs | 4 ++- compiler/rustc_target/src/abi/call/x86.rs | 3 ++ compiler/rustc_target/src/abi/call/x86_64.rs | 2 +- .../rustc_target/src/abi/call/x86_win64.rs | 1 + compiler/rustc_ty_utils/src/layout.rs | 21 ++++++++++++- .../rustc_ty_utils/src/layout_sanity_check.rs | 4 +-- tests/ui/thir-print/thir-tree-match.stdout | 8 ++--- 48 files changed, 292 insertions(+), 44 deletions(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0796.md 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_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/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/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/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_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_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_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..c5e22b6b1951e 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 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..13c246ec128a3 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs @@ -164,8 +164,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let param_env = this.param_env; if !ty.is_sized(tcx, param_env) { - // !sized means !copy, so this is an unsized move - assert!(!ty.is_copy_modulo_regions(tcx, param_env)); + // !sized means !copy, so this is an unsized move unless it's a scalable SIMD type. + if !ty.is_scalable_simd() { + assert!(!ty.is_copy_modulo_regions(tcx, param_env)); + } // As described above, detect the case where we are passing a value of unsized // type, and that value is coming from the deref of a box. 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..e3c4b2cc35c31 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1338,6 +1338,7 @@ symbols! { repr_align, repr_align_enum, repr_packed, + repr_scalable, repr_simd, repr_transparent, require, @@ -1480,6 +1481,7 @@ symbols! { saturating_add, saturating_div, saturating_sub, + scalable, self_in_typedefs, self_struct_ctor, semitransparent, @@ -1548,6 +1550,7 @@ symbols! { simd_reduce_mul_unordered, simd_reduce_or, simd_reduce_xor, + simd_reinterpret, simd_rem, simd_round, simd_saturating_add, diff --git a/compiler/rustc_target/src/abi/call/aarch64.rs b/compiler/rustc_target/src/abi/call/aarch64.rs index 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_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/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: [] From 28b752aadaf980e22e327bbd3db55700331b0456 Mon Sep 17 00:00:00 2001 From: Jamie Cunliffe Date: Fri, 3 Nov 2023 17:24:34 +0000 Subject: [PATCH 2/3] Add feature gate for Scalable SIMD types --- compiler/rustc_ast_passes/src/feature_gate.rs | 9 +++++++++ compiler/rustc_feature/src/unstable.rs | 2 ++ tests/ui/feature-gates/feature-gate-repr-scalable.rs | 8 ++++++++ .../feature-gates/feature-gate-repr-scalable.stderr | 11 +++++++++++ 4 files changed, 30 insertions(+) create mode 100644 tests/ui/feature-gates/feature-gate-repr-scalable.rs create mode 100644 tests/ui/feature-gates/feature-gate-repr-scalable.stderr 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_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/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`. From 3adc60e19b140980d25b8512dea205f45c920f12 Mon Sep 17 00:00:00 2001 From: George Wort Date: Thu, 21 Dec 2023 11:08:13 +0000 Subject: [PATCH 3/3] Add support for SVE types and registers in inline assembly This patch passes three new register constraints (y, Upa, Upl) to LLVM, along with allowing the SVE types to be passed in and out of inline assembly. --- compiler/rustc_codegen_gcc/src/asm.rs | 23 +- compiler/rustc_codegen_llvm/src/asm.rs | 39 +- compiler/rustc_codegen_ssa/src/mir/mod.rs | 2 +- .../rustc_codegen_ssa/src/traits/type_.rs | 2 +- .../src/check/intrinsicck.rs | 2 + compiler/rustc_hir_typeck/src/expr.rs | 4 +- .../src/build/expr/as_operand.rs | 8 +- compiler/rustc_monomorphize/src/collector.rs | 2 +- compiler/rustc_span/src/symbol.rs | 6 + compiler/rustc_target/src/asm/aarch64.rs | 218 ++++++--- compiler/rustc_target/src/asm/mod.rs | 13 +- library/core/src/lib.rs | 1 + tests/assembly/asm/aarch64-modifiers.rs | 113 ++++- tests/assembly/asm/aarch64-types.rs | 414 +++++++++++++++++- tests/ui/asm/aarch64/bad-reg.rs | 37 +- tests/ui/asm/aarch64/bad-reg.stderr | 126 ++++-- tests/ui/asm/aarch64/type-check-3.rs | 25 +- tests/ui/asm/aarch64/type-check-3.stderr | 61 ++- 18 files changed, 945 insertions(+), 151 deletions(-) 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_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_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/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_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/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index c5e22b6b1951e..d2f7afec009e1 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3200,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_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs index 13c246ec128a3..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,11 +163,9 @@ 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 unless it's a scalable SIMD type. - if !ty.is_scalable_simd() { - assert!(!ty.is_copy_modulo_regions(tcx, param_env)); - } + 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 // type, and that value is coming from the deref of a box. 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_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index e3c4b2cc35c31..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, @@ -1628,6 +1630,7 @@ symbols! { sub_assign, sub_with_overflow, suggestion, + sve, sym, sync, t32, @@ -1826,6 +1829,9 @@ symbols! { yield_expr, ymm_reg, zmm_reg, + zreg, + zreg_low16, + zreg_low8, } } 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/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