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