Auto merge of #143924 - davidtwco:sve-infrastructure, r=workingjubilee

`rustc_scalable_vector(N)`

Supercedes rust-lang/rust#118917.

Initial experimental implementation of rust-lang/rfcs#3838. Introduces a `rustc_scalable_vector(N)` attribute that can be applied to types with a single `[$ty]` field (for `u{16,32,64}`, `i{16,32,64}`, `f{32,64}`, `bool`). `rustc_scalable_vector` types are lowered to scalable vectors in the codegen backend.

As with any unstable feature, there will necessarily be follow-ups as we experiment and find cases that we've not considered or still need some logic to handle, but this aims to be a decent baseline to start from.

See rust-lang/rust#145052 for request for a lang experiment.
This commit is contained in:
bors 2025-12-16 12:53:53 +00:00
commit 95a27adcf9
84 changed files with 2234 additions and 146 deletions

View file

@ -60,6 +60,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
/// This is public so that it can be used in unit tests, but
/// should generally only be relevant to the ABI details of
/// specific targets.
#[tracing::instrument(skip(cx), level = "debug")]
pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, Heterogeneous>
where
Ty: TyAbiInterface<'a, C> + Copy,
@ -82,6 +83,10 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
}))
}
BackendRepr::ScalableVector { .. } => {
unreachable!("`homogeneous_aggregate` should not be called for scalable vectors")
}
BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => {
// Helper for computing `homogeneous_aggregate`, allowing a custom
// starting offset (used below for handling variants).

View file

@ -11,7 +11,7 @@ use tracing::{debug, trace};
use crate::{
AbiAlign, Align, BackendRepr, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer,
LayoutData, Niche, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding,
Variants, WrappingRange,
TargetDataLayout, Variants, WrappingRange,
};
mod coroutine;
@ -143,58 +143,32 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
})
}
pub fn simd_type<
pub fn scalable_vector_type<FieldIdx, VariantIdx, F>(
&self,
element: F,
count: u64,
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F>
where
FieldIdx: Idx,
VariantIdx: Idx,
F: AsRef<LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
>(
{
vector_type_layout(VectorKind::Scalable, self.cx.data_layout(), element, count)
}
pub fn simd_type<FieldIdx, VariantIdx, F>(
&self,
element: F,
count: u64,
repr_packed: bool,
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
let elt = element.as_ref();
if count == 0 {
return Err(LayoutCalculatorError::ZeroLengthSimdType);
} else if count > crate::MAX_SIMD_LANES {
return Err(LayoutCalculatorError::OversizedSimdType {
max_lanes: crate::MAX_SIMD_LANES,
});
}
let BackendRepr::Scalar(e_repr) = elt.backend_repr else {
return Err(LayoutCalculatorError::NonPrimitiveSimdType(element));
};
// Compute the size and alignment of the vector
let dl = self.cx.data_layout();
let size =
elt.size.checked_mul(count, dl).ok_or_else(|| LayoutCalculatorError::SizeOverflow)?;
let (repr, align) = if repr_packed && !count.is_power_of_two() {
// 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.
(BackendRepr::Memory { sized: true }, Align::max_aligned_factor(size))
} else {
(BackendRepr::SimdVector { element: e_repr, count }, dl.llvmlike_vector_align(size))
};
let size = size.align_to(align);
Ok(LayoutData {
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Arbitrary {
offsets: [Size::ZERO].into(),
memory_index: [0].into(),
},
backend_repr: repr,
largest_niche: elt.largest_niche,
uninhabited: false,
size,
align: AbiAlign::new(align),
max_repr_align: None,
unadjusted_abi_align: elt.align.abi,
randomization_seed: elt.randomization_seed.wrapping_add(Hash64::new(count)),
})
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F>
where
FieldIdx: Idx,
VariantIdx: Idx,
F: AsRef<LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
{
let kind = if repr_packed { VectorKind::PackedFixed } else { VectorKind::Fixed };
vector_type_layout(kind, self.cx.data_layout(), element, count)
}
/// Compute the layout for a coroutine.
@ -453,6 +427,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
BackendRepr::Scalar(..)
| BackendRepr::ScalarPair(..)
| BackendRepr::SimdVector { .. }
| BackendRepr::ScalableVector { .. }
| BackendRepr::Memory { .. } => repr,
},
};
@ -524,7 +499,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
hide_niches(a);
hide_niches(b);
}
BackendRepr::SimdVector { element, count: _ } => hide_niches(element),
BackendRepr::SimdVector { element, .. }
| BackendRepr::ScalableVector { element, .. } => hide_niches(element),
BackendRepr::Memory { sized: _ } => {}
}
st.largest_niche = None;
@ -1501,3 +1477,67 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
s
}
}
enum VectorKind {
/// `#[rustc_scalable_vector]`
Scalable,
/// `#[repr(simd, packed)]`
PackedFixed,
/// `#[repr(simd)]`
Fixed,
}
fn vector_type_layout<FieldIdx, VariantIdx, F>(
kind: VectorKind,
dl: &TargetDataLayout,
element: F,
count: u64,
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F>
where
FieldIdx: Idx,
VariantIdx: Idx,
F: AsRef<LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
{
let elt = element.as_ref();
if count == 0 {
return Err(LayoutCalculatorError::ZeroLengthSimdType);
} else if count > crate::MAX_SIMD_LANES {
return Err(LayoutCalculatorError::OversizedSimdType { max_lanes: crate::MAX_SIMD_LANES });
}
let BackendRepr::Scalar(element) = elt.backend_repr else {
return Err(LayoutCalculatorError::NonPrimitiveSimdType(element));
};
// Compute the size and alignment of the vector
let size =
elt.size.checked_mul(count, dl).ok_or_else(|| LayoutCalculatorError::SizeOverflow)?;
let (repr, align) = match kind {
VectorKind::Scalable => {
(BackendRepr::ScalableVector { element, count }, dl.llvmlike_vector_align(size))
}
// 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.
VectorKind::PackedFixed if !count.is_power_of_two() => {
(BackendRepr::Memory { sized: true }, Align::max_aligned_factor(size))
}
VectorKind::PackedFixed | VectorKind::Fixed => {
(BackendRepr::SimdVector { element, count }, dl.llvmlike_vector_align(size))
}
};
let size = size.align_to(align);
Ok(LayoutData {
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Arbitrary { offsets: [Size::ZERO].into(), memory_index: [0].into() },
backend_repr: repr,
largest_niche: elt.largest_niche,
uninhabited: false,
size,
align: AbiAlign::new(align),
max_repr_align: None,
unadjusted_abi_align: elt.align.abi,
randomization_seed: elt.randomization_seed.wrapping_add(Hash64::new(count)),
})
}

View file

@ -155,7 +155,7 @@ impl<'a, Ty> AsRef<LayoutData<FieldIdx, VariantIdx>> for TyAndLayout<'a, Ty> {
/// Trait that needs to be implemented by the higher-level type representation
/// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality.
pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug {
pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug + std::fmt::Display {
fn ty_and_layout_for_variant(
this: TyAndLayout<'a, Self>,
cx: &C,
@ -172,6 +172,7 @@ pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug {
fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
fn is_transparent(this: TyAndLayout<'a, Self>) -> bool;
fn is_scalable_vector(this: TyAndLayout<'a, Self>) -> bool;
/// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'a, Self>) -> bool;
}
@ -271,6 +272,13 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
Ty::is_transparent(self)
}
pub fn is_scalable_vector<C>(self) -> bool
where
Ty: TyAbiInterface<'a, C>,
{
Ty::is_scalable_vector(self)
}
/// If this method returns `true`, then this type should always have a `PassMode` of
/// `Indirect { on_stack: false, .. }` when being used as the argument type of a function with a
/// non-Rustic ABI (this is true for structs annotated with the

View file

@ -96,9 +96,11 @@ bitflags! {
/// If true, the type is always passed indirectly by non-Rustic ABIs.
/// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
const PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS = 1 << 5;
/// Any of these flags being set prevent field reordering optimisation.
const FIELD_ORDER_UNOPTIMIZABLE = ReprFlags::IS_C.bits()
const IS_SCALABLE = 1 << 6;
// Any of these flags being set prevent field reordering optimisation.
const FIELD_ORDER_UNOPTIMIZABLE = ReprFlags::IS_C.bits()
| ReprFlags::IS_SIMD.bits()
| ReprFlags::IS_SCALABLE.bits()
| ReprFlags::IS_LINEAR.bits();
const ABI_UNOPTIMIZABLE = ReprFlags::IS_C.bits() | ReprFlags::IS_SIMD.bits();
}
@ -135,6 +137,19 @@ impl IntegerType {
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[cfg_attr(
feature = "nightly",
derive(Encodable_NoContext, Decodable_NoContext, HashStable_Generic)
)]
pub enum ScalableElt {
/// `N` in `rustc_scalable_vector(N)` - the element count of the scalable vector
ElementCount(u16),
/// `rustc_scalable_vector` w/out `N`, used for tuple types of scalable vectors that only
/// contain other scalable vectors
Container,
}
/// Represents the repr options provided by the user.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
#[cfg_attr(
@ -146,6 +161,8 @@ pub struct ReprOptions {
pub align: Option<Align>,
pub pack: Option<Align>,
pub flags: ReprFlags,
/// `#[rustc_scalable_vector]`
pub scalable: Option<ScalableElt>,
/// The seed to be used for randomizing a type's layout
///
/// Note: This could technically be a `u128` which would
@ -162,6 +179,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)
@ -1736,6 +1758,10 @@ impl AddressSpace {
pub enum BackendRepr {
Scalar(Scalar),
ScalarPair(Scalar, Scalar),
ScalableVector {
element: Scalar,
count: u64,
},
SimdVector {
element: Scalar,
count: u64,
@ -1754,6 +1780,12 @@ impl BackendRepr {
match *self {
BackendRepr::Scalar(_)
| BackendRepr::ScalarPair(..)
// FIXME(rustc_scalable_vector): Scalable vectors are `Sized` while the
// `sized_hierarchy` feature is not yet fully implemented. After `sized_hierarchy` is
// fully implemented, scalable vectors will remain `Sized`, they just won't be
// `const Sized` - whether `is_unsized` continues to return `false` at that point will
// need to be revisited and will depend on what `is_unsized` is used for.
| BackendRepr::ScalableVector { .. }
| BackendRepr::SimdVector { .. } => false,
BackendRepr::Memory { sized } => !sized,
}
@ -1794,7 +1826,9 @@ impl BackendRepr {
BackendRepr::Scalar(s) => Some(s.align(cx).abi),
BackendRepr::ScalarPair(s1, s2) => Some(s1.align(cx).max(s2.align(cx)).abi),
// The align of a Vector can vary in surprising ways
BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => None,
BackendRepr::SimdVector { .. }
| BackendRepr::Memory { .. }
| BackendRepr::ScalableVector { .. } => None,
}
}
@ -1816,7 +1850,9 @@ impl BackendRepr {
Some(size)
}
// The size of a Vector can vary in surprising ways
BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => None,
BackendRepr::SimdVector { .. }
| BackendRepr::Memory { .. }
| BackendRepr::ScalableVector { .. } => None,
}
}
@ -1831,6 +1867,9 @@ impl BackendRepr {
BackendRepr::SimdVector { element: element.to_union(), count }
}
BackendRepr::Memory { .. } => BackendRepr::Memory { sized: true },
BackendRepr::ScalableVector { element, count } => {
BackendRepr::ScalableVector { element: element.to_union(), count }
}
}
}
@ -2071,7 +2110,9 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
/// Returns `true` if this is an aggregate type (including a ScalarPair!)
pub fn is_aggregate(&self) -> bool {
match self.backend_repr {
BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => false,
BackendRepr::Scalar(_)
| BackendRepr::SimdVector { .. }
| BackendRepr::ScalableVector { .. } => false,
BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => true,
}
}
@ -2165,6 +2206,19 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
self.is_sized() && self.size.bytes() == 0 && self.align.bytes() == 1
}
/// Returns `true` if the size of the type is only known at runtime.
pub fn is_runtime_sized(&self) -> bool {
matches!(self.backend_repr, BackendRepr::ScalableVector { .. })
}
/// Returns the elements count of a scalable vector.
pub fn scalable_vector_element_count(&self) -> Option<u64> {
match self.backend_repr {
BackendRepr::ScalableVector { count, .. } => Some(count),
_ => None,
}
}
/// Returns `true` if the type is a ZST and not unsized.
///
/// Note that this does *not* imply that the type is irrelevant for layout! It can still have
@ -2173,6 +2227,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
match self.backend_repr {
BackendRepr::Scalar(_)
| BackendRepr::ScalarPair(..)
| BackendRepr::ScalableVector { .. }
| BackendRepr::SimdVector { .. } => false,
BackendRepr::Memory { sized } => sized && self.size.bytes() == 0,
}

View file

@ -270,6 +270,8 @@ ast_passes_precise_capturing_duplicated = duplicate `use<...>` precise capturing
ast_passes_precise_capturing_not_allowed_here = `use<...>` precise capturing syntax not allowed in {$loc}
ast_passes_scalable_vector_not_tuple_struct = scalable vectors must be tuple structs
ast_passes_static_without_body =
free static item without body
.suggestion = provide a definition for the static

View file

@ -1319,6 +1319,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
ItemKind::Struct(ident, generics, vdata) => {
self.with_tilde_const(Some(TildeConstReason::Struct { span: item.span }), |this| {
// Scalable vectors can only be tuple structs
let is_scalable_vector =
item.attrs.iter().any(|attr| attr.has_name(sym::rustc_scalable_vector));
if is_scalable_vector && !matches!(vdata, VariantData::Tuple(..)) {
this.dcx()
.emit_err(errors::ScalableVectorNotTupleStruct { span: item.span });
}
match vdata {
VariantData::Struct { fields, .. } => {
this.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);

View file

@ -990,3 +990,10 @@ pub(crate) struct AbiX86Interrupt {
pub spans: Vec<Span>,
pub param_count: usize,
}
#[derive(Diagnostic)]
#[diag(ast_passes_scalable_vector_not_tuple_struct)]
pub(crate) struct ScalableVectorNotTupleStruct {
#[primary_span]
pub span: Span,
}

View file

@ -200,6 +200,9 @@ attr_parsing_rustc_allowed_unstable_pairing =
attr_parsing_rustc_promotable_pairing =
`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute
attr_parsing_rustc_scalable_vector_count_out_of_range = element count in `rustc_scalable_vector` is too large: `{$n}`
.note = the value may not exceed `u16::MAX`
attr_parsing_soft_no_args =
`soft` should not have any arguments

View file

@ -1,5 +1,6 @@
use super::prelude::*;
use super::util::parse_single_integer;
use crate::session_diagnostics::RustcScalableVectorCountOutOfRange;
pub(crate) struct RustcMainParser;
@ -76,3 +77,29 @@ impl<S: Stage> SingleAttributeParser<S> for RustcSimdMonomorphizeLaneLimitParser
Some(AttributeKind::RustcSimdMonomorphizeLaneLimit(cx.parse_limit_int(nv)?))
}
}
pub(crate) struct RustcScalableVectorParser;
impl<S: Stage> SingleAttributeParser<S> for RustcScalableVectorParser {
const PATH: &[rustc_span::Symbol] = &[sym::rustc_scalable_vector];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
const TEMPLATE: AttributeTemplate = template!(Word, List: &["count"]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
if args.no_args().is_ok() {
return Some(AttributeKind::RustcScalableVector {
element_count: None,
span: cx.attr_span,
});
}
let n = parse_single_integer(cx, args)?;
let Ok(n) = n.try_into() else {
cx.emit_err(RustcScalableVectorCountOutOfRange { span: cx.attr_span, n });
return None;
};
Some(AttributeKind::RustcScalableVector { element_count: Some(n), span: cx.attr_span })
}
}

View file

@ -60,7 +60,8 @@ use crate::attributes::prototype::CustomMirParser;
use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser};
use crate::attributes::rustc_internal::{
RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, RustcMainParser,
RustcObjectLifetimeDefaultParser, RustcSimdMonomorphizeLaneLimitParser,
RustcObjectLifetimeDefaultParser, RustcScalableVectorParser,
RustcSimdMonomorphizeLaneLimitParser,
};
use crate::attributes::semantics::MayDangleParser;
use crate::attributes::stability::{
@ -209,6 +210,7 @@ attribute_parsers!(
Single<RustcLayoutScalarValidRangeEndParser>,
Single<RustcLayoutScalarValidRangeStartParser>,
Single<RustcObjectLifetimeDefaultParser>,
Single<RustcScalableVectorParser>,
Single<RustcSimdMonomorphizeLaneLimitParser>,
Single<SanitizeParser>,
Single<ShouldPanicParser>,

View file

@ -501,6 +501,15 @@ pub(crate) struct LinkOrdinalOutOfRange {
pub ordinal: u128,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_rustc_scalable_vector_count_out_of_range)]
#[note]
pub(crate) struct RustcScalableVectorCountOutOfRange {
#[primary_span]
pub span: Span,
pub n: u128,
}
pub(crate) enum AttributeParseErrorReason<'a> {
ExpectedNoArgs,
ExpectedStringLiteral {

View file

@ -943,6 +943,10 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
.get_address(self.location)
}
fn scalable_alloca(&mut self, _elt: u64, _align: Align, _element_ty: Ty<'_>) -> RValue<'gcc> {
todo!()
}
fn load(&mut self, pointee_ty: Type<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> {
let block = self.llbb();
let function = block.get_function();

View file

@ -504,7 +504,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
let layout = self.layout_of(tp_ty).layout;
let _use_integer_compare = match layout.backend_repr() {
Scalar(_) | ScalarPair(_, _) => true,
SimdVector { .. } => false,
SimdVector { .. } | ScalableVector { .. } => false,
Memory { .. } => {
// For rusty ABIs, small aggregates are actually passed
// as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),

View file

@ -85,6 +85,7 @@ fn uncached_gcc_type<'gcc, 'tcx>(
);
}
BackendRepr::Memory { .. } => {}
BackendRepr::ScalableVector { .. } => todo!(),
}
let name = match *layout.ty.kind() {
@ -179,6 +180,8 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
fn is_gcc_immediate(&self) -> bool {
match self.backend_repr {
BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => true,
// FIXME(rustc_scalable_vector): Not yet implemented in rustc_codegen_gcc.
BackendRepr::ScalableVector { .. } => todo!(),
BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => false,
}
}
@ -188,6 +191,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
BackendRepr::ScalarPair(..) => true,
BackendRepr::Scalar(_)
| BackendRepr::SimdVector { .. }
| BackendRepr::ScalableVector { .. }
| BackendRepr::Memory { .. } => false,
}
}

View file

@ -613,6 +613,25 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
}
}
fn scalable_alloca(&mut self, elt: u64, align: Align, element_ty: Ty<'_>) -> Self::Value {
let mut bx = Builder::with_cx(self.cx);
bx.position_at_start(unsafe { llvm::LLVMGetFirstBasicBlock(self.llfn()) });
let llvm_ty = match element_ty.kind() {
ty::Bool => bx.type_i1(),
ty::Int(int_ty) => self.cx.type_int_from_ty(*int_ty),
ty::Uint(uint_ty) => self.cx.type_uint_from_ty(*uint_ty),
ty::Float(float_ty) => self.cx.type_float_from_ty(*float_ty),
_ => unreachable!("scalable vectors can only contain a bool, int, uint or float"),
};
unsafe {
let ty = llvm::LLVMScalableVectorType(llvm_ty, elt.try_into().unwrap());
let alloca = llvm::LLVMBuildAlloca(&bx.llbuilder, ty, UNNAMED);
llvm::LLVMSetAlignment(alloca, align.bytes() as c_uint);
alloca
}
}
fn load(&mut self, ty: &'ll Type, ptr: &'ll Value, align: Align) -> &'ll Value {
unsafe {
let load = llvm::LLVMBuildLoad2(self.llbuilder, ty, ptr, UNNAMED);

View file

@ -480,6 +480,14 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
let use_integer_compare = match layout.backend_repr() {
Scalar(_) | ScalarPair(_, _) => true,
SimdVector { .. } => false,
ScalableVector { .. } => {
tcx.dcx().emit_err(InvalidMonomorphization::NonScalableType {
span,
name: sym::raw_eq,
ty: tp_ty,
});
return Ok(());
}
Memory { .. } => {
// For rusty ABIs, small aggregates are actually passed
// as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),
@ -1679,11 +1687,27 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
m_len == v_len,
InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len }
);
let in_elem_bitwidth = require_int_or_uint_ty!(
m_elem_ty.kind(),
InvalidMonomorphization::MaskWrongElementType { span, name, ty: m_elem_ty }
);
let m_i1s = vector_mask_to_bitmask(bx, args[0].immediate(), in_elem_bitwidth, m_len);
let m_i1s = if args[1].layout.ty.is_scalable_vector() {
match m_elem_ty.kind() {
ty::Bool => {}
_ => return_error!(InvalidMonomorphization::MaskWrongElementType {
span,
name,
ty: m_elem_ty
}),
};
let i1 = bx.type_i1();
let i1xn = bx.type_scalable_vector(i1, m_len as u64);
bx.trunc(args[0].immediate(), i1xn)
} else {
let in_elem_bitwidth = require_int_or_uint_ty!(
m_elem_ty.kind(),
InvalidMonomorphization::MaskWrongElementType { span, name, ty: m_elem_ty }
);
vector_mask_to_bitmask(bx, args[0].immediate(), in_elem_bitwidth, m_len)
};
return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
}

View file

@ -998,6 +998,7 @@ unsafe extern "C" {
// Operations on array, pointer, and vector types (sequence types)
pub(crate) safe fn LLVMPointerTypeInContext(C: &Context, AddressSpace: c_uint) -> &Type;
pub(crate) fn LLVMVectorType(ElementType: &Type, ElementCount: c_uint) -> &Type;
pub(crate) fn LLVMScalableVectorType(ElementType: &Type, ElementCount: c_uint) -> &Type;
pub(crate) fn LLVMGetElementType(Ty: &Type) -> &Type;
pub(crate) fn LLVMGetVectorSize(VectorTy: &Type) -> c_uint;

View file

@ -68,6 +68,10 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
unsafe { llvm::LLVMVectorType(ty, len as c_uint) }
}
pub(crate) fn type_scalable_vector(&self, ty: &'ll Type, count: u64) -> &'ll Type {
unsafe { llvm::LLVMScalableVectorType(ty, count as c_uint) }
}
pub(crate) fn add_func(&self, name: &str, ty: &'ll Type) -> &'ll Value {
let name = SmallCStr::new(name);
unsafe { llvm::LLVMAddFunction(self.llmod(), name.as_ptr(), ty) }

View file

@ -24,6 +24,15 @@ fn uncached_llvm_type<'a, 'tcx>(
let element = layout.scalar_llvm_type_at(cx, element);
return cx.type_vector(element, count);
}
BackendRepr::ScalableVector { ref element, count } => {
let element = if element.is_bool() {
cx.type_i1()
} else {
layout.scalar_llvm_type_at(cx, *element)
};
return cx.type_scalable_vector(element, count);
}
BackendRepr::Memory { .. } | BackendRepr::ScalarPair(..) => {}
}
@ -176,7 +185,9 @@ pub(crate) trait LayoutLlvmExt<'tcx> {
impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
fn is_llvm_immediate(&self) -> bool {
match self.backend_repr {
BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => true,
BackendRepr::Scalar(_)
| BackendRepr::SimdVector { .. }
| BackendRepr::ScalableVector { .. } => true,
BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => false,
}
}
@ -186,6 +197,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
BackendRepr::ScalarPair(..) => true,
BackendRepr::Scalar(_)
| BackendRepr::SimdVector { .. }
| BackendRepr::ScalableVector { .. }
| BackendRepr::Memory { .. } => false,
}
}

View file

@ -549,7 +549,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>(
registers_for_primitive(scalar1.primitive());
registers_for_primitive(scalar2.primitive());
}
BackendRepr::SimdVector { .. } => {
BackendRepr::SimdVector { .. } | BackendRepr::ScalableVector { .. } => {
// Because no instance of VaArgSafe uses a non-scalar `BackendRepr`.
unreachable!(
"No x86-64 SysV va_arg implementation for {:?}",
@ -689,7 +689,9 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>(
}
}
// The Previous match on `BackendRepr` means control flow already escaped.
BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => unreachable!(),
BackendRepr::SimdVector { .. }
| BackendRepr::ScalableVector { .. }
| BackendRepr::Memory { .. } => unreachable!(),
};
// AMD64-ABI 3.5.7p5: Step 5. Set:

View file

@ -129,6 +129,7 @@ codegen_ssa_invalid_monomorphization_mask_wrong_element_type = invalid monomorph
codegen_ssa_invalid_monomorphization_mismatched_lengths = invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}`
codegen_ssa_invalid_monomorphization_non_scalable_type = invalid monomorphization of `{$name}` intrinsic: expected non-scalable type, found scalable type `{$ty}`
codegen_ssa_invalid_monomorphization_return_element = invalid monomorphization of `{$name}` intrinsic: expected return element type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` with element type `{$out_ty}`
codegen_ssa_invalid_monomorphization_return_integer_type = invalid monomorphization of `{$name}` intrinsic: expected return type with integer elements, found `{$ret_ty}` with non-integer `{$out_ty}`

View file

@ -1094,6 +1094,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 {

View file

@ -2,7 +2,7 @@ use std::collections::hash_map::Entry;
use std::marker::PhantomData;
use std::ops::Range;
use rustc_abi::{BackendRepr, FieldIdx, FieldsShape, Size, VariantIdx};
use rustc_abi::{BackendRepr, FieldIdx, FieldsShape, ScalableElt, Size, VariantIdx};
use rustc_data_structures::fx::FxHashMap;
use rustc_index::IndexVec;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
@ -408,6 +408,49 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
return;
}
// Don't spill `<vscale x N x i1>` for `N != 16`:
//
// SVE predicates are only one bit for each byte in an SVE vector (which makes
// sense, the predicate only needs to keep track of whether a lane is
// enabled/disabled). i.e. a `<vscale x 16 x i8>` vector has a `<vscale x 16 x i1>`
// predicate type. `<vscale x 16 x i1>` corresponds to two bytes of storage,
// multiplied by the `vscale`, with one bit for each of the sixteen lanes.
//
// For a vector with fewer elements, such as `svint32_t`/`<vscale x 4 x i32>`,
// while only a `<vscale x 4 x i1>` predicate type would be strictly necessary,
// relevant intrinsics still take a `svbool_t`/`<vscale x 16 x i1>` - this is
// because a `<vscale x 4 x i1>` is only half of a byte (for `vscale=1`), and with
// memory being byte-addressable, it's unclear how to store that.
//
// Due to this, LLVM ultimately decided not to support stores of `<vscale x N x i1>`
// for `N != 16`. As for `vscale=1` and `N` fewer than sixteen, partial bytes would
// need to be stored (except for `N=8`, but that also isn't supported). `N` can
// never be greater than sixteen as that ends up larger than the 128-bit increment
// size.
//
// Internally, with an intrinsic operating on a `svint32_t`/`<vscale x 4 x i32>`
// (for example), the intrinsic takes the `svbool_t`/`<vscale x 16 x i1>` predicate
// and casts it to a `svbool4_t`/`<vscale x 4 x i1>`. Therefore, it's important that
// the `<vscale x 4 x i32>` never spills because that'll cause errors during
// instruction selection. Spilling to the stack to create debuginfo for these
// intermediate values must be avoided and won't degrade the debugging experience
// anyway.
if operand.layout.ty.is_scalable_vector()
&& bx.sess().target.arch == rustc_target::spec::Arch::AArch64
&& let ty::Adt(adt, args) = &operand.layout.ty.kind()
&& let Some(marker_type_field) =
adt.non_enum_variant().fields.get(FieldIdx::from_u32(0))
{
let marker_type = marker_type_field.ty(bx.tcx(), args);
// i.e. `<vscale x N x i1>` when `N != 16`
if let ty::Slice(element_ty) = marker_type.kind()
&& element_ty.is_bool()
&& adt.repr().scalable != Some(ScalableElt::ElementCount(16))
{
return;
}
}
Self::spill_operand_to_stack(*operand, name, bx)
}

View file

@ -405,7 +405,9 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
imm
}
}
BackendRepr::ScalarPair(_, _) | BackendRepr::Memory { .. } => bug!(),
BackendRepr::ScalarPair(_, _)
| BackendRepr::Memory { .. }
| BackendRepr::ScalableVector { .. } => bug!(),
})
};
@ -692,7 +694,9 @@ impl<'a, 'tcx, V: CodegenObject> OperandRefBuilder<'tcx, V> {
BackendRepr::ScalarPair(a, b) => {
OperandValueBuilder::Pair(Either::Right(a), Either::Right(b))
}
BackendRepr::SimdVector { .. } => OperandValueBuilder::Vector(Either::Right(())),
BackendRepr::SimdVector { .. } | BackendRepr::ScalableVector { .. } => {
OperandValueBuilder::Vector(Either::Right(()))
}
BackendRepr::Memory { .. } => {
bug!("Cannot use non-ZST Memory-ABI type in operand builder: {layout:?}");
}

View file

@ -109,7 +109,11 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
bx: &mut Bx,
layout: TyAndLayout<'tcx>,
) -> Self {
Self::alloca_size(bx, layout.size, layout)
if layout.is_runtime_sized() {
Self::alloca_runtime_sized(bx, layout)
} else {
Self::alloca_size(bx, layout.size, layout)
}
}
pub fn alloca_size<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
@ -146,6 +150,18 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
bug!("unexpected layout `{:#?}` in PlaceRef::len", self.layout)
}
}
fn alloca_runtime_sized<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
bx: &mut Bx,
layout: TyAndLayout<'tcx>,
) -> Self {
let (element_count, ty) = layout.ty.scalable_vector_element_count_and_type(bx.tcx());
PlaceValue::new_sized(
bx.scalable_alloca(element_count as u64, layout.align.abi, ty),
layout.align.abi,
)
.with_type(layout)
}
}
impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {

View file

@ -235,6 +235,7 @@ pub trait BuilderMethods<'a, 'tcx>:
fn to_immediate_scalar(&mut self, val: Self::Value, scalar: Scalar) -> Self::Value;
fn alloca(&mut self, size: Size, align: Align) -> Self::Value;
fn scalable_alloca(&mut self, elt: u64, align: Align, element_ty: Ty<'_>) -> Self::Value;
fn load(&mut self, ty: Self::Type, ptr: Self::Value, align: Align) -> Self::Value;
fn volatile_load(&mut self, ty: Self::Type, ptr: Self::Value) -> Self::Value;

View file

@ -1315,7 +1315,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
self.visit_scalar(b, b_layout)?;
}
}
BackendRepr::SimdVector { .. } => {
BackendRepr::SimdVector { .. } | BackendRepr::ScalableVector { .. } => {
// No checks here, we assume layout computation gets this right.
// (This is harder to check since Miri does not represent these as `Immediate`. We
// also cannot use field projections since this might be a newtype around a vector.)

View file

@ -119,7 +119,9 @@ fn check_validity_requirement_lax<'tcx>(
}
BackendRepr::SimdVector { element: s, count } => count == 0 || scalar_allows_raw_init(s),
BackendRepr::Memory { .. } => true, // Fields are checked below.
BackendRepr::ScalableVector { element, .. } => scalar_allows_raw_init(element),
};
if !valid {
// This is definitely not okay.
return Ok(false);

View file

@ -1422,6 +1422,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_force_inline, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, EncodeCrossCrate::Yes,
"`#[rustc_force_inline]` forces a free function to be inlined"
),
rustc_attr!(
rustc_scalable_vector, Normal, template!(List: &["count"]), WarnFollowing, EncodeCrossCrate::Yes,
"`#[rustc_scalable_vector]` defines a scalable vector type"
),
// ==========================================================================
// Internal attributes, Testing:

View file

@ -878,6 +878,14 @@ pub enum AttributeKind {
/// Represents `#[rustc_pass_indirectly_in_non_rustic_abis]`
RustcPassIndirectlyInNonRusticAbis(Span),
/// Represents `#[rustc_scalable_vector(N)]`
RustcScalableVector {
/// The base multiple of lanes that are in a scalable vector, if provided. `element_count`
/// is not provided for representing tuple types.
element_count: Option<u16>,
span: Span,
},
/// Represents `#[rustc_should_not_be_called_on_const_items]`
RustcShouldNotBeCalledOnConstItems(Span),

View file

@ -95,6 +95,7 @@ impl AttributeKind {
RustcMain => No,
RustcObjectLifetimeDefault => No,
RustcPassIndirectlyInNonRusticAbis(..) => No,
RustcScalableVector { .. } => Yes,
RustcShouldNotBeCalledOnConstItems(..) => Yes,
RustcSimdMonomorphizeLaneLimit(..) => Yes, // Affects layout computation, which needs to work cross-crate
Sanitize { .. } => No,

View file

@ -1,4 +1,5 @@
use std::num::NonZero;
use std::ops::Deref;
use rustc_abi::Align;
use rustc_ast::token::{CommentKind, DocFragmentKind};
@ -37,6 +38,15 @@ impl<T: PrintAttribute> PrintAttribute for &T {
T::print_attribute(self, p)
}
}
impl<T: PrintAttribute> PrintAttribute for Box<T> {
fn should_render(&self) -> bool {
self.deref().should_render()
}
fn print_attribute(&self, p: &mut Printer) {
T::print_attribute(self.deref(), p)
}
}
impl<T: PrintAttribute> PrintAttribute for Option<T> {
fn should_render(&self) -> bool {
self.as_ref().is_some_and(|x| x.should_render())

View file

@ -1,7 +1,7 @@
use std::cell::LazyCell;
use std::ops::ControlFlow;
use rustc_abi::{ExternAbi, FieldIdx};
use rustc_abi::{ExternAbi, FieldIdx, ScalableElt};
use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_errors::codes::*;
use rustc_errors::{EmissionGuarantee, MultiSpan};
@ -92,7 +92,9 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let span = tcx.def_span(def_id);
def.destructor(tcx); // force the destructor to be evaluated
if def.repr().simd() {
if let Some(scalable) = def.repr().scalable {
check_scalable_vector(tcx, span, def_id, scalable);
} else if def.repr().simd() {
check_simd(tcx, span, def_id);
}
@ -1426,6 +1428,100 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
}
}
#[tracing::instrument(skip(tcx), level = "debug")]
fn check_scalable_vector(tcx: TyCtxt<'_>, span: Span, def_id: LocalDefId, scalable: ScalableElt) {
let ty = tcx.type_of(def_id).instantiate_identity();
let ty::Adt(def, args) = ty.kind() else { return };
if !def.is_struct() {
tcx.dcx().delayed_bug("`rustc_scalable_vector` applied to non-struct");
return;
}
let fields = &def.non_enum_variant().fields;
match scalable {
ScalableElt::ElementCount(..) if fields.is_empty() => {
let mut err =
tcx.dcx().struct_span_err(span, "scalable vectors must have a single field");
err.help("scalable vector types' only field must be a primitive scalar type");
err.emit();
return;
}
ScalableElt::ElementCount(..) if fields.len() >= 2 => {
tcx.dcx().struct_span_err(span, "scalable vectors cannot have multiple fields").emit();
return;
}
ScalableElt::Container if fields.is_empty() => {
let mut err =
tcx.dcx().struct_span_err(span, "scalable vectors must have a single field");
err.help("tuples of scalable vectors can only contain multiple of the same scalable vector type");
err.emit();
return;
}
_ => {}
}
match scalable {
ScalableElt::ElementCount(..) => {
let element_ty = &fields[FieldIdx::ZERO].ty(tcx, args);
// Check that `element_ty` only uses types valid in the lanes of a scalable vector
// register: scalar types which directly match a "machine" type - integers, floats and
// bools
match element_ty.kind() {
ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Bool => (),
_ => {
let mut err = tcx.dcx().struct_span_err(
span,
"element type of a scalable vector must be a primitive scalar",
);
err.help("only `u*`, `i*`, `f*` and `bool` types are accepted");
err.emit();
}
}
}
ScalableElt::Container => {
let mut prev_field_ty = None;
for field in fields.iter() {
let element_ty = field.ty(tcx, args);
if let ty::Adt(def, _) = element_ty.kind()
&& def.repr().scalable()
{
match def
.repr()
.scalable
.expect("`repr().scalable.is_some()` != `repr().scalable()`")
{
ScalableElt::ElementCount(_) => { /* expected field */ }
ScalableElt::Container => {
tcx.dcx().span_err(
tcx.def_span(field.did),
"scalable vector structs cannot contain other scalable vector structs",
);
break;
}
}
} else {
tcx.dcx().span_err(
tcx.def_span(field.did),
"scalable vector structs can only have scalable vector fields",
);
break;
}
if let Some(prev_ty) = prev_field_ty.replace(element_ty)
&& prev_ty != element_ty
{
tcx.dcx().span_err(
tcx.def_span(field.did),
"all fields in a scalable vector struct must be the same type",
);
break;
}
}
}
}
}
pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
let repr = def.repr();
if repr.packed() {

View file

@ -2,7 +2,7 @@ use std::cell::LazyCell;
use std::ops::{ControlFlow, Deref};
use hir::intravisit::{self, Visitor};
use rustc_abi::ExternAbi;
use rustc_abi::{ExternAbi, ScalableElt};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::codes::*;
use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err};
@ -1038,7 +1038,21 @@ fn check_type_defn<'tcx>(
hir_ty.span,
Some(WellFormedLoc::Ty(field_id)),
ty.into(),
)
);
if matches!(ty.kind(), ty::Adt(def, _) if def.repr().scalable())
&& !matches!(adt_def.repr().scalable, Some(ScalableElt::Container))
{
// Scalable vectors can only be fields of structs if the type has a
// `rustc_scalable_vector` attribute w/out specifying an element count
tcx.dcx().span_err(
hir_ty.span,
format!(
"scalable vectors cannot be fields of a {}",
adt_def.variant_descr()
),
);
}
}
// For DST, or when drop needs to copy things around, all

View file

@ -1178,6 +1178,10 @@ where
matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().transparent())
}
fn is_scalable_vector(this: TyAndLayout<'tcx>) -> bool {
this.ty.is_scalable_vector()
}
/// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'tcx>) -> bool {
matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().flags.contains(ReprFlags::PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS))

View file

@ -24,7 +24,9 @@ pub use assoc::*;
pub use generic_args::{GenericArgKind, TermKind, *};
pub use generics::*;
pub use intrinsic::IntrinsicDef;
use rustc_abi::{Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, VariantIdx};
use rustc_abi::{
Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, ScalableElt, VariantIdx,
};
use rustc_ast::AttrVec;
use rustc_ast::expand::typetree::{FncTree, Kind, Type, TypeTree};
use rustc_ast::node_id::NodeMap;
@ -1515,6 +1517,17 @@ impl<'tcx> TyCtxt<'tcx> {
}
let attributes = self.get_all_attrs(did);
let elt = find_attr!(
attributes,
AttributeKind::RustcScalableVector { element_count, .. } => element_count
)
.map(|elt| match elt {
Some(n) => ScalableElt::ElementCount(*n),
None => ScalableElt::Container,
});
if elt.is_some() {
flags.insert(ReprFlags::IS_SCALABLE);
}
if let Some(reprs) = find_attr!(attributes, AttributeKind::Repr { reprs, .. } => reprs) {
for (r, _) in reprs {
flags.insert(match *r {
@ -1579,7 +1592,14 @@ impl<'tcx> TyCtxt<'tcx> {
flags.insert(ReprFlags::PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS);
}
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.

View file

@ -7,7 +7,7 @@ use std::borrow::Cow;
use std::ops::{ControlFlow, Range};
use hir::def::{CtorKind, DefKind};
use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
use rustc_abi::{FIRST_VARIANT, FieldIdx, ScalableElt, VariantIdx};
use rustc_errors::{ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::LangItem;
@ -1253,6 +1253,14 @@ impl<'tcx> Ty<'tcx> {
}
}
#[inline]
pub fn is_scalable_vector(self) -> bool {
match self.kind() {
Adt(def, _) => def.repr().scalable(),
_ => false,
}
}
pub fn sequence_element_type(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
match self.kind() {
Array(ty, _) | Slice(ty) => *ty,
@ -1261,6 +1269,19 @@ impl<'tcx> Ty<'tcx> {
}
}
pub fn scalable_vector_element_count_and_type(self, tcx: TyCtxt<'tcx>) -> (u16, Ty<'tcx>) {
let Adt(def, args) = self.kind() else {
bug!("`scalable_vector_size_and_type` called on invalid type")
};
let Some(ScalableElt::ElementCount(element_count)) = def.repr().scalable else {
bug!("`scalable_vector_size_and_type` called on non-scalable vector type");
};
let variant = def.non_enum_variant();
assert_eq!(variant.fields.len(), 1);
let field_ty = variant.fields[FieldIdx::ZERO].ty(tcx, args);
(element_count, field_ty)
}
pub fn simd_size_and_type(self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
let Adt(def, args) = self.kind() else {
bug!("`simd_size_and_type` called on invalid type")

View file

@ -1891,6 +1891,16 @@ fn check_must_not_suspend_ty<'tcx>(
SuspendCheckData { descr_pre: &format!("{}allocator ", data.descr_pre), ..data },
)
}
// FIXME(sized_hierarchy): This should be replaced with a requirement that types in
// coroutines implement `const Sized`. Scalable vectors are temporarily `Sized` while
// `feature(sized_hierarchy)` is not fully implemented, but in practice are
// non-`const Sized` and so do not have a known size at compilation time. Layout computation
// for a coroutine containing scalable vectors would be incorrect.
ty::Adt(def, _) if def.repr().scalable() => {
tcx.dcx()
.span_err(data.source_span, "scalable vectors cannot be held over await points");
true
}
ty::Adt(def, _) => check_must_not_suspend_def(tcx, def.did(), hir_id, data),
// FIXME: support adding the attribute to TAITs
ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {

View file

@ -1661,7 +1661,9 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
BackendRepr::ScalarPair(a, b) => {
!a.is_always_valid(&self.ecx) || !b.is_always_valid(&self.ecx)
}
BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => false,
BackendRepr::SimdVector { .. }
| BackendRepr::ScalableVector { .. }
| BackendRepr::Memory { .. } => false,
}
}

View file

@ -2,7 +2,10 @@ monomorphize_abi_error_disabled_vector_type =
this function {$is_call ->
[true] call
*[false] definition
} uses SIMD vector type `{$ty}` which (with the chosen ABI) requires the `{$required_feature}` target feature, which is not enabled{$is_call ->
} uses {$is_scalable ->
[true] scalable
*[false] SIMD
} vector type `{$ty}` which (with the chosen ABI) requires the `{$required_feature}` target feature, which is not enabled{$is_call ->
[true] {" "}in the caller
*[false] {""}
}

View file

@ -78,6 +78,8 @@ pub(crate) struct AbiErrorDisabledVectorType<'a> {
pub ty: Ty<'a>,
/// Whether this is a problem at a call site or at a declaration.
pub is_call: bool,
/// Whether this is a problem with a fixed length vector or a scalable vector
pub is_scalable: bool,
}
#[derive(Diagnostic)]

View file

@ -10,14 +10,37 @@ use rustc_target::callconv::{FnAbi, PassMode};
use crate::errors;
fn uses_vector_registers(mode: &PassMode, repr: &BackendRepr) -> bool {
/// Are vector registers used?
enum UsesVectorRegisters {
/// e.g. `neon`
FixedVector,
/// e.g. `sve`
ScalableVector,
No,
}
/// Determines whether the combination of `mode` and `repr` will use fixed vector registers,
/// scalable vector registers or no vector registers.
fn passes_vectors_by_value(mode: &PassMode, repr: &BackendRepr) -> UsesVectorRegisters {
match mode {
PassMode::Ignore | PassMode::Indirect { .. } => false,
PassMode::Cast { pad_i32: _, cast } => {
cast.prefix.iter().any(|r| r.is_some_and(|x| x.kind == RegKind::Vector))
|| cast.rest.unit.kind == RegKind::Vector
PassMode::Ignore | PassMode::Indirect { .. } => UsesVectorRegisters::No,
PassMode::Cast { pad_i32: _, cast }
if cast.prefix.iter().any(|r| r.is_some_and(|x| x.kind == RegKind::Vector))
|| cast.rest.unit.kind == RegKind::Vector =>
{
UsesVectorRegisters::FixedVector
}
PassMode::Direct(..) | PassMode::Pair(..) => matches!(repr, BackendRepr::SimdVector { .. }),
PassMode::Direct(..) | PassMode::Pair(..)
if matches!(repr, BackendRepr::SimdVector { .. }) =>
{
UsesVectorRegisters::FixedVector
}
PassMode::Direct(..) | PassMode::Pair(..)
if matches!(repr, BackendRepr::ScalableVector { .. }) =>
{
UsesVectorRegisters::ScalableVector
}
_ => UsesVectorRegisters::No,
}
}
@ -32,37 +55,60 @@ fn do_check_simd_vector_abi<'tcx>(
is_call: bool,
loc: impl Fn() -> (Span, HirId),
) {
let feature_def = tcx.sess.target.features_for_correct_vector_abi();
let codegen_attrs = tcx.codegen_fn_attrs(def_id);
let have_feature = |feat: Symbol| {
tcx.sess.unstable_target_features.contains(&feat)
|| codegen_attrs.target_features.iter().any(|x| x.name == feat)
let target_feats = tcx.sess.unstable_target_features.contains(&feat);
let fn_feats = codegen_attrs.target_features.iter().any(|x| x.name == feat);
target_feats || fn_feats
};
for arg_abi in abi.args.iter().chain(std::iter::once(&abi.ret)) {
let size = arg_abi.layout.size;
if uses_vector_registers(&arg_abi.mode, &arg_abi.layout.backend_repr) {
// Find the first feature that provides at least this vector size.
let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) {
Some((_, feature)) => feature,
None => {
match passes_vectors_by_value(&arg_abi.mode, &arg_abi.layout.backend_repr) {
UsesVectorRegisters::FixedVector => {
let feature_def = tcx.sess.target.features_for_correct_fixed_length_vector_abi();
// Find the first feature that provides at least this vector size.
let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) {
Some((_, feature)) => feature,
None => {
let (span, _hir_id) = loc();
tcx.dcx().emit_err(errors::AbiErrorUnsupportedVectorType {
span,
ty: arg_abi.layout.ty,
is_call,
});
continue;
}
};
if !feature.is_empty() && !have_feature(Symbol::intern(feature)) {
let (span, _hir_id) = loc();
tcx.dcx().emit_err(errors::AbiErrorUnsupportedVectorType {
tcx.dcx().emit_err(errors::AbiErrorDisabledVectorType {
span,
required_feature: feature,
ty: arg_abi.layout.ty,
is_call,
is_scalable: false,
});
continue;
}
};
if !feature.is_empty() && !have_feature(Symbol::intern(feature)) {
// Emit error.
let (span, _hir_id) = loc();
tcx.dcx().emit_err(errors::AbiErrorDisabledVectorType {
span,
required_feature: feature,
ty: arg_abi.layout.ty,
is_call,
});
}
UsesVectorRegisters::ScalableVector => {
let Some(required_feature) =
tcx.sess.target.features_for_correct_scalable_vector_abi()
else {
continue;
};
if !required_feature.is_empty() && !have_feature(Symbol::intern(required_feature)) {
let (span, _) = loc();
tcx.dcx().emit_err(errors::AbiErrorDisabledVectorType {
span,
required_feature,
ty: arg_abi.layout.ty,
is_call,
is_scalable: true,
});
}
}
UsesVectorRegisters::No => {
continue;
}
}
}

View file

@ -252,6 +252,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| AttributeKind::MacroEscape( .. )
| AttributeKind::RustcLayoutScalarValidRangeStart(..)
| AttributeKind::RustcLayoutScalarValidRangeEnd(..)
| AttributeKind::RustcScalableVector { .. }
| AttributeKind::RustcSimdMonomorphizeLaneLimit(..)
| AttributeKind::RustcShouldNotBeCalledOnConstItems(..)
| AttributeKind::ExportStable

View file

@ -225,6 +225,10 @@ pub enum ValueAbi {
element: Scalar,
count: u64,
},
ScalableVector {
element: Scalar,
count: u64,
},
Aggregate {
/// If true, the size is exact, otherwise it's only a lower bound.
sized: bool,
@ -235,7 +239,15 @@ impl ValueAbi {
/// Returns `true` if the layout corresponds to an unsized type.
pub fn is_unsized(&self) -> bool {
match *self {
ValueAbi::Scalar(_) | ValueAbi::ScalarPair(..) | ValueAbi::Vector { .. } => false,
ValueAbi::Scalar(_)
| ValueAbi::ScalarPair(..)
| ValueAbi::Vector { .. }
// FIXME(rustc_scalable_vector): Scalable vectors are `Sized` while the
// `sized_hierarchy` feature is not yet fully implemented. After `sized_hierarchy` is
// fully implemented, scalable vectors will remain `Sized`, they just won't be
// `const Sized` - whether `is_unsized` continues to return `false` at that point will
// need to be revisited and will depend on what `is_unsized` is used for.
| ValueAbi::ScalableVector { .. } => false,
ValueAbi::Aggregate { sized } => !sized,
}
}

View file

@ -256,6 +256,9 @@ impl<'tcx> Stable<'tcx> for rustc_abi::BackendRepr {
rustc_abi::BackendRepr::SimdVector { element, count } => {
ValueAbi::Vector { element: element.stable(tables, cx), count }
}
rustc_abi::BackendRepr::ScalableVector { element, count } => {
ValueAbi::ScalableVector { element: element.stable(tables, cx), count }
}
rustc_abi::BackendRepr::Memory { sized } => ValueAbi::Aggregate { sized },
}
}

View file

@ -1998,6 +1998,7 @@ symbols! {
rustc_reallocator,
rustc_regions,
rustc_reservation_impl,
rustc_scalable_vector,
rustc_serialize,
rustc_should_not_be_called_on_const_items,
rustc_simd_monomorphize_lane_limit,

View file

@ -9,13 +9,14 @@ use crate::spec::{Abi, HasTargetSpec, Target};
/// Used to accommodate Apple and Microsoft's deviations from the usual AAPCS ABI.
///
/// Corresponds to Clang's `AArch64ABIInfo::ABIKind`.
#[derive(Copy, Clone, PartialEq)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub(crate) enum AbiKind {
AAPCS,
DarwinPCS,
Win64,
}
#[tracing::instrument(skip(cx), level = "debug")]
fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option<Uniform>
where
Ty: TyAbiInterface<'a, C> + Copy,
@ -73,12 +74,13 @@ fn softfloat_float_abi<Ty>(target: &Target, arg: &mut ArgAbi<'_, Ty>) {
}
}
#[tracing::instrument(skip(cx), level = "debug")]
fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, kind: AbiKind)
where
Ty: TyAbiInterface<'a, C> + Copy,
C: HasDataLayout + HasTargetSpec,
{
if !ret.layout.is_sized() {
if !ret.layout.is_sized() || ret.layout.is_scalable_vector() {
// Not touching this...
return;
}
@ -105,12 +107,13 @@ where
ret.make_indirect();
}
#[tracing::instrument(skip(cx), level = "debug")]
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, kind: AbiKind)
where
Ty: TyAbiInterface<'a, C> + Copy,
C: HasDataLayout + HasTargetSpec,
{
if !arg.layout.is_sized() {
if !arg.layout.is_sized() || arg.layout.is_scalable_vector() {
// Not touching this...
return;
}

View file

@ -85,7 +85,10 @@ where
}
}
},
BackendRepr::SimdVector { .. } => return Err(CannotUseFpConv),
BackendRepr::SimdVector { .. } => {
return Err(CannotUseFpConv);
}
BackendRepr::ScalableVector { .. } => panic!("scalable vectors are unsupported"),
BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields {
FieldsShape::Primitive => {
unreachable!("aggregates can't have `FieldsShape::Primitive`")

View file

@ -393,6 +393,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
),
BackendRepr::SimdVector { .. } => PassMode::Direct(ArgAttributes::new()),
BackendRepr::Memory { .. } => Self::indirect_pass_mode(&layout),
BackendRepr::ScalableVector { .. } => PassMode::Direct(ArgAttributes::new()),
};
ArgAbi { layout, mode }
}

View file

@ -91,7 +91,9 @@ where
}
}
},
BackendRepr::SimdVector { .. } => return Err(CannotUseFpConv),
BackendRepr::SimdVector { .. } | BackendRepr::ScalableVector { .. } => {
return Err(CannotUseFpConv);
}
BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields {
FieldsShape::Primitive => {
unreachable!("aggregates can't have `FieldsShape::Primitive`")

View file

@ -103,6 +103,9 @@ where
}
false
}
BackendRepr::ScalableVector { .. } => {
panic!("scalable vectors are unsupported")
}
}
}

View file

@ -59,6 +59,8 @@ where
BackendRepr::SimdVector { .. } => Class::Sse,
BackendRepr::ScalableVector { .. } => panic!("scalable vectors are unsupported"),
BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => {
for i in 0..layout.fields.count() {
let field_off = off + layout.fields.offset(i);

View file

@ -25,6 +25,7 @@ where
// FIXME(eddyb) there should be a size cap here
// (probably what clang calls "illegal vectors").
}
BackendRepr::ScalableVector { .. } => panic!("scalable vectors are unsupported"),
BackendRepr::Scalar(scalar) => {
if is_ret && matches!(scalar.primitive(), Primitive::Int(Integer::I128, _)) {
if cx.target_spec().rustc_abi == Some(RustcAbi::X86Softfloat) {

View file

@ -911,18 +911,24 @@ pub fn all_rust_features() -> impl Iterator<Item = (&'static str, Stability)> {
// These arrays represent the least-constraining feature that is required for vector types up to a
// certain size to have their "proper" ABI on each architecture.
// Note that they must be kept sorted by vector size.
const X86_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
const X86_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
&[(128, "sse"), (256, "avx"), (512, "avx512f")]; // FIXME: might need changes for AVX10.
const AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")];
const AARCH64_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
&[(128, "neon")];
// We might want to add "helium" too.
const ARM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")];
const ARM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
&[(128, "neon")];
const AMDGPU_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(1024, "")];
const POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "altivec")];
const WASM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "simd128")];
const S390X_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vector")];
const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[
const AMDGPU_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
&[(1024, "")];
const POWERPC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
&[(128, "altivec")];
const WASM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
&[(128, "simd128")];
const S390X_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
&[(128, "vector")];
const RISCV_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = &[
(32, "zvl32b"),
(64, "zvl64b"),
(128, "zvl128b"),
@ -937,13 +943,16 @@ const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[
(65536, "zvl65536b"),
];
// Always error on SPARC, as the necessary target features cannot be enabled in Rust at the moment.
const SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(64, "vis")*/];
const SPARC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
&[/*(64, "vis")*/];
const HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
const HEXAGON_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
&[/*(512, "hvx-length64b"),*/ (1024, "hvx-length128b")];
const MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "msa")];
const CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vdspv1")];
const LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
const MIPS_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
&[(128, "msa")];
const CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
&[(128, "vdspv1")];
const LOONGARCH_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
&[(128, "lsx"), (256, "lasx")];
#[derive(Copy, Clone, Debug)]
@ -982,24 +991,26 @@ impl Target {
}
}
pub fn features_for_correct_vector_abi(&self) -> &'static [(u64, &'static str)] {
pub fn features_for_correct_fixed_length_vector_abi(&self) -> &'static [(u64, &'static str)] {
match &self.arch {
Arch::X86 | Arch::X86_64 => X86_FEATURES_FOR_CORRECT_VECTOR_ABI,
Arch::AArch64 | Arch::Arm64EC => AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI,
Arch::Arm => ARM_FEATURES_FOR_CORRECT_VECTOR_ABI,
Arch::PowerPC | Arch::PowerPC64 => POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI,
Arch::LoongArch32 | Arch::LoongArch64 => LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI,
Arch::RiscV32 | Arch::RiscV64 => RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI,
Arch::Wasm32 | Arch::Wasm64 => WASM_FEATURES_FOR_CORRECT_VECTOR_ABI,
Arch::S390x => S390X_FEATURES_FOR_CORRECT_VECTOR_ABI,
Arch::Sparc | Arch::Sparc64 => SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI,
Arch::Hexagon => HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI,
Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => {
MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI
Arch::X86 | Arch::X86_64 => X86_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
Arch::AArch64 | Arch::Arm64EC => AARCH64_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
Arch::Arm => ARM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
Arch::PowerPC | Arch::PowerPC64 => POWERPC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
Arch::LoongArch32 | Arch::LoongArch64 => {
LOONGARCH_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI
}
Arch::AmdGpu => AMDGPU_FEATURES_FOR_CORRECT_VECTOR_ABI,
Arch::RiscV32 | Arch::RiscV64 => RISCV_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
Arch::Wasm32 | Arch::Wasm64 => WASM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
Arch::S390x => S390X_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
Arch::Sparc | Arch::Sparc64 => SPARC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
Arch::Hexagon => HEXAGON_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => {
MIPS_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI
}
Arch::AmdGpu => AMDGPU_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
Arch::Nvptx64 | Arch::Bpf | Arch::M68k => &[], // no vector ABI
Arch::CSky => CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI,
Arch::CSky => CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
// FIXME: for some tier3 targets, we are overly cautious and always give warnings
// when passing args in vector registers.
Arch::Avr
@ -1011,6 +1022,14 @@ impl Target {
}
}
pub fn features_for_correct_scalable_vector_abi(&self) -> Option<&'static str> {
match &self.arch {
Arch::AArch64 | Arch::Arm64EC => Some("sve"),
// Other targets have no scalable vectors or they are unimplemented.
_ => None,
}
}
pub fn tied_target_features(&self) -> &'static [&'static [&'static str]] {
match &self.arch {
Arch::AArch64 | Arch::Arm64EC => AARCH64_TIED_FEATURES,

View file

@ -771,9 +771,25 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
}
ty::Tuple(tys) => {
if let Some((_last, rest)) = tys.split_last() {
if let Some((last, rest)) = tys.split_last() {
for &elem in rest {
self.require_sized(elem, ObligationCauseCode::TupleElem);
if elem.is_scalable_vector() && !self.span.is_dummy() {
self.tcx()
.dcx()
.struct_span_err(
self.span,
"scalable vectors cannot be tuple fields",
)
.emit();
}
}
if last.is_scalable_vector() && !self.span.is_dummy() {
self.tcx()
.dcx()
.struct_span_err(self.span, "scalable vectors cannot be tuple fields")
.emit();
}
}
}

View file

@ -412,7 +412,9 @@ fn fn_abi_sanity_check<'tcx>(
// `layout.backend_repr` and ignore everything else. We should just reject
//`Aggregate` entirely here, but some targets need to be fixed first.
match arg.layout.backend_repr {
BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => {}
BackendRepr::Scalar(_)
| BackendRepr::SimdVector { .. }
| BackendRepr::ScalableVector { .. } => {}
BackendRepr::ScalarPair(..) => {
panic!("`PassMode::Direct` used for ScalarPair type {}", arg.layout.ty)
}

View file

@ -3,8 +3,8 @@ use rustc_abi::Integer::{I8, I32};
use rustc_abi::Primitive::{self, Float, Int, Pointer};
use rustc_abi::{
AddressSpace, BackendRepr, FIRST_VARIANT, FieldIdx, FieldsShape, HasDataLayout, Layout,
LayoutCalculatorError, LayoutData, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding,
VariantIdx, Variants, WrappingRange,
LayoutCalculatorError, LayoutData, Niche, ReprOptions, ScalableElt, Scalar, Size, StructKind,
TagEncoding, VariantIdx, Variants, WrappingRange,
};
use rustc_hashes::Hash64;
use rustc_hir::attrs::AttributeKind;
@ -567,6 +567,37 @@ fn layout_of_uncached<'tcx>(
univariant(tys, kind)?
}
// Scalable vector types
//
// ```rust (ignore, example)
// #[rustc_scalable_vector(3)]
// struct svuint32_t(u32);
// ```
ty::Adt(def, args)
if matches!(def.repr().scalable, Some(ScalableElt::ElementCount(..))) =>
{
let Some(element_ty) = def
.is_struct()
.then(|| &def.variant(FIRST_VARIANT).fields)
.filter(|fields| fields.len() == 1)
.map(|fields| fields[FieldIdx::ZERO].ty(tcx, args))
else {
let guar = tcx
.dcx()
.delayed_bug("#[rustc_scalable_vector] was applied to an invalid type");
return Err(error(cx, LayoutError::ReferencesError(guar)));
};
let Some(ScalableElt::ElementCount(element_count)) = def.repr().scalable else {
let guar = tcx
.dcx()
.delayed_bug("#[rustc_scalable_vector] was applied to an invalid type");
return Err(error(cx, LayoutError::ReferencesError(guar)));
};
let element_layout = cx.layout_of(element_ty)?;
map_layout(cx.calc.scalable_vector_type(element_layout, element_count as u64))?
}
// SIMD vector types.
ty::Adt(def, args) if def.repr().simd() => {
// Supported SIMD vectors are ADTs with a single array field:

View file

@ -250,7 +250,7 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou
// And the size has to be element * count plus alignment padding, of course
assert!(size == (element_size * count).align_to(align));
}
BackendRepr::Memory { .. } => {} // Nothing to check.
BackendRepr::Memory { .. } | BackendRepr::ScalableVector { .. } => {} // Nothing to check.
}
}

View file

@ -0,0 +1,49 @@
//@ edition: 2021
//@ only-aarch64
#![crate_type = "lib"]
#![allow(incomplete_features, internal_features)]
#![feature(simd_ffi, rustc_attrs, link_llvm_intrinsics)]
#[derive(Copy, Clone)]
#[rustc_scalable_vector(4)]
#[allow(non_camel_case_types)]
pub struct svint32_t(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<const IMM3: i32>(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 <vscale x 4 x i32> @pass_as_ref(ptr {{.*}}align 16{{.*}} %a, <vscale x 4 x i32> %b)
pub unsafe fn pass_as_ref(a: &svint32_t, b: svint32_t) -> svint32_t {
// CHECK: load <vscale x 4 x i32>, ptr %a, align 16
svxar_n_s32::<1>(*a, b)
}
#[no_mangle]
#[target_feature(enable = "sve,sve2")]
// CHECK: define <vscale x 4 x i32> @test()
pub unsafe fn test() -> svint32_t {
let a = svdup_n_s32(1);
let b = svdup_n_s32(2);
// CHECK: %_0 = call <vscale x 4 x i32> @pass_as_ref(ptr {{.*}}align 16{{.*}} %a, <vscale x 4 x i32> %b)
pass_as_ref(&a, b)
}

View file

@ -0,0 +1,44 @@
//@ only-aarch64
//@ edition:2021
#![allow(incomplete_features, internal_features)]
#![feature(
core_intrinsics,
simd_ffi,
rustc_attrs,
link_llvm_intrinsics
)]
use core::intrinsics::transmute_unchecked;
#[rustc_scalable_vector(4)]
#[allow(non_camel_case_types)]
pub struct svint32_t(i32);
#[target_feature(enable = "sve")]
pub unsafe fn svdup_n_s32(op: i32) -> svint32_t {
extern "C" {
#[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.dup.x.nxv4i32")]
fn _svdup_n_s32(op: i32) -> svint32_t;
}
unsafe { _svdup_n_s32(op) }
}
#[target_feature(enable = "sve")]
async fn another() -> i32 {
42
}
#[no_mangle]
#[target_feature(enable = "sve")]
pub async fn test_function() {
unsafe {
let x = svdup_n_s32(1); //~ ERROR: scalable vectors cannot be held over await points
let temp = another().await;
let y: svint32_t = transmute_unchecked(x);
}
}
fn main() {
let _ = unsafe { test_function() };
}

View file

@ -0,0 +1,8 @@
error: scalable vectors cannot be held over await points
--> $DIR/async.rs:36:13
|
LL | let x = svdup_n_s32(1);
| ^
error: aborting due to 1 previous error

View file

@ -0,0 +1,51 @@
//@ compile-flags: --crate-type=lib
//@ only-aarch64
#![allow(incomplete_features, internal_features)]
#![feature(
link_llvm_intrinsics,
rustc_attrs,
simd_ffi
)]
#[derive(Copy, Clone)]
#[rustc_scalable_vector(4)]
#[allow(non_camel_case_types)]
pub struct svint32_t(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<const IMM3: i32>(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)]
#[target_feature(enable = "sve,sve2")]
fn run(f: impl Fn() -> ()) {
f();
}
#[target_feature(enable = "sve,sve2")]
fn foo() {
unsafe {
let a = svdup_n_s32(42);
run(move || {
//~^ ERROR: scalable vectors cannot be tuple fields
svxar_n_s32::<2>(a, a);
});
}
}

View file

@ -0,0 +1,8 @@
error: scalable vectors cannot be tuple fields
--> $DIR/closure-capture.rs:46:9
|
LL | run(move || {
| ^^^
error: aborting due to 1 previous error

View file

@ -0,0 +1,31 @@
//@ build-pass
//@ only-aarch64
#![feature(simd_ffi, rustc_attrs, link_llvm_intrinsics)]
#[derive(Copy, Clone)]
#[rustc_scalable_vector(4)]
#[allow(non_camel_case_types)]
pub struct svint32_t(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;
//~^ WARN: `extern` block uses type `svint32_t`, which is not FFI-safe
}
unsafe { _svdup_n_s32(op) }
}
#[target_feature(enable = "sve")]
fn require_copy<T: Copy>(t: T) {}
#[target_feature(enable = "sve")]
fn test() {
unsafe {
let a = svdup_n_s32(1);
require_copy(a);
}
}
fn main() {}

View file

@ -0,0 +1,17 @@
warning: `extern` block uses type `svint32_t`, which is not FFI-safe
--> $DIR/copy-clone.rs:14:37
|
LL | fn _svdup_n_s32(op: i32) -> svint32_t;
| ^^^^^^^^^ not FFI-safe
|
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
= note: this struct has unspecified layout
note: the type is defined here
--> $DIR/copy-clone.rs:8:1
|
LL | pub struct svint32_t(i32);
| ^^^^^^^^^^^^^^^^^^^^
= note: `#[warn(improper_ctypes)]` on by default
warning: 1 warning emitted

View file

@ -0,0 +1,13 @@
#![allow(internal_features)]
#![feature(rustc_attrs)]
#[rustc_scalable_vector(4)]
pub struct ScalableSimdFloat(f32);
unsafe fn test<T>(f: T)
where
T: Fn(ScalableSimdFloat), //~ ERROR: scalable vectors cannot be tuple fields
{
}
fn main() {}

View file

@ -0,0 +1,8 @@
error: scalable vectors cannot be tuple fields
--> $DIR/fn-trait.rs:9:8
|
LL | T: Fn(ScalableSimdFloat),
| ^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View file

@ -0,0 +1,93 @@
//@ compile-flags: --crate-type=lib
#![allow(internal_features)]
#![feature(extern_types)]
#![feature(never_type)]
#![feature(rustc_attrs)]
struct Foo;
enum Bar {}
union Baz { x: u16 }
extern "C" {
type Qux;
}
#[rustc_scalable_vector(4)]
struct TyChar(char);
//~^ ERROR: element type of a scalable vector must be a primitive scalar
#[rustc_scalable_vector(2)]
struct TyConstPtr(*const u8);
//~^ ERROR: element type of a scalable vector must be a primitive scalar
#[rustc_scalable_vector(2)]
struct TyMutPtr(*mut u8);
//~^ ERROR: element type of a scalable vector must be a primitive scalar
#[rustc_scalable_vector(4)]
struct TyStruct(Foo);
//~^ ERROR: element type of a scalable vector must be a primitive scalar
#[rustc_scalable_vector(4)]
struct TyEnum(Bar);
//~^ ERROR: element type of a scalable vector must be a primitive scalar
#[rustc_scalable_vector(4)]
struct TyUnion(Baz);
//~^ ERROR: element type of a scalable vector must be a primitive scalar
#[rustc_scalable_vector(4)]
struct TyForeign(Qux);
//~^ ERROR: element type of a scalable vector must be a primitive scalar
#[rustc_scalable_vector(4)]
struct TyArray([u32; 4]);
//~^ ERROR: element type of a scalable vector must be a primitive scalar
#[rustc_scalable_vector(4)]
struct TySlice([u32]);
//~^ ERROR: element type of a scalable vector must be a primitive scalar
#[rustc_scalable_vector(4)]
struct TyRef<'a>(&'a u32);
//~^ ERROR: element type of a scalable vector must be a primitive scalar
#[rustc_scalable_vector(4)]
struct TyFnPtr(fn(u32) -> u32);
//~^ ERROR: element type of a scalable vector must be a primitive scalar
#[rustc_scalable_vector(4)]
struct TyDyn(dyn std::io::Write);
//~^ ERROR: element type of a scalable vector must be a primitive scalar
#[rustc_scalable_vector(4)]
struct TyNever(!);
//~^ ERROR: element type of a scalable vector must be a primitive scalar
#[rustc_scalable_vector(4)]
struct TyTuple((u32, u32));
//~^ ERROR: element type of a scalable vector must be a primitive scalar
type ValidAlias = u32;
type InvalidAlias = String;
#[rustc_scalable_vector(4)]
struct TyValidAlias(ValidAlias);
#[rustc_scalable_vector(4)]
struct TyInvalidAlias(InvalidAlias);
//~^ ERROR: element type of a scalable vector must be a primitive scalar
trait Tr {
type Valid;
type Invalid;
}
impl Tr for () {
type Valid = u32;
type Invalid = String;
}
struct TyValidProjection(<() as Tr>::Valid);
struct TyInvalidProjection(<() as Tr>::Invalid);
// FIXME: element type of a scalable vector must be a primitive scalar

View file

@ -0,0 +1,122 @@
error: element type of a scalable vector must be a primitive scalar
--> $DIR/illformed-element-type.rs:15:1
|
LL | struct TyChar(char);
| ^^^^^^^^^^^^^
|
= help: only `u*`, `i*`, `f*` and `bool` types are accepted
error: element type of a scalable vector must be a primitive scalar
--> $DIR/illformed-element-type.rs:19:1
|
LL | struct TyConstPtr(*const u8);
| ^^^^^^^^^^^^^^^^^
|
= help: only `u*`, `i*`, `f*` and `bool` types are accepted
error: element type of a scalable vector must be a primitive scalar
--> $DIR/illformed-element-type.rs:23:1
|
LL | struct TyMutPtr(*mut u8);
| ^^^^^^^^^^^^^^^
|
= help: only `u*`, `i*`, `f*` and `bool` types are accepted
error: element type of a scalable vector must be a primitive scalar
--> $DIR/illformed-element-type.rs:27:1
|
LL | struct TyStruct(Foo);
| ^^^^^^^^^^^^^^^
|
= help: only `u*`, `i*`, `f*` and `bool` types are accepted
error: element type of a scalable vector must be a primitive scalar
--> $DIR/illformed-element-type.rs:31:1
|
LL | struct TyEnum(Bar);
| ^^^^^^^^^^^^^
|
= help: only `u*`, `i*`, `f*` and `bool` types are accepted
error: element type of a scalable vector must be a primitive scalar
--> $DIR/illformed-element-type.rs:35:1
|
LL | struct TyUnion(Baz);
| ^^^^^^^^^^^^^^
|
= help: only `u*`, `i*`, `f*` and `bool` types are accepted
error: element type of a scalable vector must be a primitive scalar
--> $DIR/illformed-element-type.rs:39:1
|
LL | struct TyForeign(Qux);
| ^^^^^^^^^^^^^^^^
|
= help: only `u*`, `i*`, `f*` and `bool` types are accepted
error: element type of a scalable vector must be a primitive scalar
--> $DIR/illformed-element-type.rs:43:1
|
LL | struct TyArray([u32; 4]);
| ^^^^^^^^^^^^^^
|
= help: only `u*`, `i*`, `f*` and `bool` types are accepted
error: element type of a scalable vector must be a primitive scalar
--> $DIR/illformed-element-type.rs:47:1
|
LL | struct TySlice([u32]);
| ^^^^^^^^^^^^^^
|
= help: only `u*`, `i*`, `f*` and `bool` types are accepted
error: element type of a scalable vector must be a primitive scalar
--> $DIR/illformed-element-type.rs:51:1
|
LL | struct TyRef<'a>(&'a u32);
| ^^^^^^^^^^^^^^^^
|
= help: only `u*`, `i*`, `f*` and `bool` types are accepted
error: element type of a scalable vector must be a primitive scalar
--> $DIR/illformed-element-type.rs:55:1
|
LL | struct TyFnPtr(fn(u32) -> u32);
| ^^^^^^^^^^^^^^
|
= help: only `u*`, `i*`, `f*` and `bool` types are accepted
error: element type of a scalable vector must be a primitive scalar
--> $DIR/illformed-element-type.rs:59:1
|
LL | struct TyDyn(dyn std::io::Write);
| ^^^^^^^^^^^^
|
= help: only `u*`, `i*`, `f*` and `bool` types are accepted
error: element type of a scalable vector must be a primitive scalar
--> $DIR/illformed-element-type.rs:63:1
|
LL | struct TyNever(!);
| ^^^^^^^^^^^^^^
|
= help: only `u*`, `i*`, `f*` and `bool` types are accepted
error: element type of a scalable vector must be a primitive scalar
--> $DIR/illformed-element-type.rs:67:1
|
LL | struct TyTuple((u32, u32));
| ^^^^^^^^^^^^^^
|
= help: only `u*`, `i*`, `f*` and `bool` types are accepted
error: element type of a scalable vector must be a primitive scalar
--> $DIR/illformed-element-type.rs:77:1
|
LL | struct TyInvalidAlias(InvalidAlias);
| ^^^^^^^^^^^^^^^^^^^^^
|
= help: only `u*`, `i*`, `f*` and `bool` types are accepted
error: aborting due to 15 previous errors

View file

@ -0,0 +1,36 @@
//@ compile-flags: --crate-type=lib
#![allow(internal_features)]
#![feature(rustc_attrs)]
#[rustc_scalable_vector(2)]
struct ValidI64(i64);
#[rustc_scalable_vector(4)]
struct ValidI32(i32);
#[rustc_scalable_vector]
struct ValidTuple(ValidI32, ValidI32, ValidI32);
#[rustc_scalable_vector]
struct Struct { x: ValidI64, y: ValidI64 }
//~^ ERROR: scalable vectors must be tuple structs
#[rustc_scalable_vector]
struct DifferentVectorTypes(ValidI64, ValidI32);
//~^ ERROR: all fields in a scalable vector struct must be the same type
#[rustc_scalable_vector]
struct NonVectorTypes(u32, u64);
//~^ ERROR: scalable vector structs can only have scalable vector fields
#[rustc_scalable_vector]
struct DifferentNonVectorTypes(u32, u64);
//~^ ERROR: scalable vector structs can only have scalable vector fields
#[rustc_scalable_vector]
struct SomeVectorTypes(ValidI64, u64);
//~^ ERROR: scalable vector structs can only have scalable vector fields
#[rustc_scalable_vector]
struct NestedTuple(ValidTuple, ValidTuple);
//~^ ERROR: scalable vector structs cannot contain other scalable vector structs

View file

@ -0,0 +1,38 @@
error: scalable vectors must be tuple structs
--> $DIR/illformed-tuples-of-scalable-vectors.rs:15:1
|
LL | struct Struct { x: ValidI64, y: ValidI64 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: all fields in a scalable vector struct must be the same type
--> $DIR/illformed-tuples-of-scalable-vectors.rs:19:39
|
LL | struct DifferentVectorTypes(ValidI64, ValidI32);
| ^^^^^^^^
error: scalable vector structs can only have scalable vector fields
--> $DIR/illformed-tuples-of-scalable-vectors.rs:23:23
|
LL | struct NonVectorTypes(u32, u64);
| ^^^
error: scalable vector structs can only have scalable vector fields
--> $DIR/illformed-tuples-of-scalable-vectors.rs:27:32
|
LL | struct DifferentNonVectorTypes(u32, u64);
| ^^^
error: scalable vector structs can only have scalable vector fields
--> $DIR/illformed-tuples-of-scalable-vectors.rs:31:34
|
LL | struct SomeVectorTypes(ValidI64, u64);
| ^^^
error: scalable vector structs cannot contain other scalable vector structs
--> $DIR/illformed-tuples-of-scalable-vectors.rs:35:20
|
LL | struct NestedTuple(ValidTuple, ValidTuple);
| ^^^^^^^^^^
error: aborting due to 6 previous errors

View file

@ -0,0 +1,23 @@
//@ compile-flags: --crate-type=lib
#![allow(internal_features)]
#![feature(rustc_attrs)]
#[rustc_scalable_vector(2)]
struct ValidI64(i64);
struct Struct {
x: ValidI64,
//~^ ERROR: scalable vectors cannot be fields of a struct
in_tuple: (ValidI64,),
//~^ ERROR: scalable vectors cannot be tuple fields
}
struct TupleStruct(ValidI64);
//~^ ERROR: scalable vectors cannot be fields of a struct
enum Enum {
StructVariant { _ty: ValidI64 },
//~^ ERROR: scalable vectors cannot be fields of a variant
TupleVariant(ValidI64),
//~^ ERROR: scalable vectors cannot be fields of a variant
}

View file

@ -0,0 +1,32 @@
error: scalable vectors cannot be fields of a struct
--> $DIR/illformed-within-types.rs:9:8
|
LL | x: ValidI64,
| ^^^^^^^^
error: scalable vectors cannot be tuple fields
--> $DIR/illformed-within-types.rs:11:15
|
LL | in_tuple: (ValidI64,),
| ^^^^^^^^^^^
error: scalable vectors cannot be fields of a struct
--> $DIR/illformed-within-types.rs:15:20
|
LL | struct TupleStruct(ValidI64);
| ^^^^^^^^
error: scalable vectors cannot be fields of a variant
--> $DIR/illformed-within-types.rs:19:26
|
LL | StructVariant { _ty: ValidI64 },
| ^^^^^^^^
error: scalable vectors cannot be fields of a variant
--> $DIR/illformed-within-types.rs:21:18
|
LL | TupleVariant(ValidI64),
| ^^^^^^^^
error: aborting due to 5 previous errors

View file

@ -0,0 +1,59 @@
//@ compile-flags: --crate-type=lib
#![allow(internal_features)]
#![feature(rustc_attrs)]
#[rustc_scalable_vector(4)]
struct NoFieldsStructWithElementCount {}
//~^ ERROR: scalable vectors must have a single field
//~^^ ERROR: scalable vectors must be tuple structs
#[rustc_scalable_vector(4)]
struct NoFieldsTupleWithElementCount();
//~^ ERROR: scalable vectors must have a single field
#[rustc_scalable_vector(4)]
struct NoFieldsUnitWithElementCount;
//~^ ERROR: scalable vectors must have a single field
//~^^ ERROR: scalable vectors must be tuple structs
#[rustc_scalable_vector]
struct NoFieldsStructWithoutElementCount {}
//~^ ERROR: scalable vectors must have a single field
//~^^ ERROR: scalable vectors must be tuple structs
#[rustc_scalable_vector]
struct NoFieldsTupleWithoutElementCount();
//~^ ERROR: scalable vectors must have a single field
#[rustc_scalable_vector]
struct NoFieldsUnitWithoutElementCount;
//~^ ERROR: scalable vectors must have a single field
//~^^ ERROR: scalable vectors must be tuple structs
#[rustc_scalable_vector(4)]
struct MultipleFieldsStructWithElementCount {
//~^ ERROR: scalable vectors cannot have multiple fields
//~^^ ERROR: scalable vectors must be tuple structs
_ty: f32,
other: u32,
}
#[rustc_scalable_vector(4)]
struct MultipleFieldsTupleWithElementCount(f32, u32);
//~^ ERROR: scalable vectors cannot have multiple fields
#[rustc_scalable_vector]
struct MultipleFieldsStructWithoutElementCount {
//~^ ERROR: scalable vectors must be tuple structs
_ty: f32,
//~^ ERROR: scalable vector structs can only have scalable vector fields
other: u32,
}
#[rustc_scalable_vector]
struct MultipleFieldsTupleWithoutElementCount(f32, u32);
//~^ ERROR: scalable vector structs can only have scalable vector fields
#[rustc_scalable_vector(2)]
struct SingleFieldStruct { _ty: f64 }
//~^ ERROR: scalable vectors must be tuple structs

View file

@ -0,0 +1,125 @@
error: scalable vectors must be tuple structs
--> $DIR/illformed.rs:6:1
|
LL | struct NoFieldsStructWithElementCount {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: scalable vectors must be tuple structs
--> $DIR/illformed.rs:15:1
|
LL | struct NoFieldsUnitWithElementCount;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: scalable vectors must be tuple structs
--> $DIR/illformed.rs:20:1
|
LL | struct NoFieldsStructWithoutElementCount {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: scalable vectors must be tuple structs
--> $DIR/illformed.rs:29:1
|
LL | struct NoFieldsUnitWithoutElementCount;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: scalable vectors must be tuple structs
--> $DIR/illformed.rs:34:1
|
LL | / struct MultipleFieldsStructWithElementCount {
LL | |
LL | |
LL | | _ty: f32,
LL | | other: u32,
LL | | }
| |_^
error: scalable vectors must be tuple structs
--> $DIR/illformed.rs:46:1
|
LL | / struct MultipleFieldsStructWithoutElementCount {
LL | |
LL | | _ty: f32,
... |
LL | | }
| |_^
error: scalable vectors must be tuple structs
--> $DIR/illformed.rs:58:1
|
LL | struct SingleFieldStruct { _ty: f64 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: scalable vectors must have a single field
--> $DIR/illformed.rs:6:1
|
LL | struct NoFieldsStructWithElementCount {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: scalable vector types' only field must be a primitive scalar type
error: scalable vectors must have a single field
--> $DIR/illformed.rs:11:1
|
LL | struct NoFieldsTupleWithElementCount();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: scalable vector types' only field must be a primitive scalar type
error: scalable vectors must have a single field
--> $DIR/illformed.rs:15:1
|
LL | struct NoFieldsUnitWithElementCount;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: scalable vector types' only field must be a primitive scalar type
error: scalable vectors must have a single field
--> $DIR/illformed.rs:20:1
|
LL | struct NoFieldsStructWithoutElementCount {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: tuples of scalable vectors can only contain multiple of the same scalable vector type
error: scalable vectors must have a single field
--> $DIR/illformed.rs:25:1
|
LL | struct NoFieldsTupleWithoutElementCount();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: tuples of scalable vectors can only contain multiple of the same scalable vector type
error: scalable vectors must have a single field
--> $DIR/illformed.rs:29:1
|
LL | struct NoFieldsUnitWithoutElementCount;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: tuples of scalable vectors can only contain multiple of the same scalable vector type
error: scalable vectors cannot have multiple fields
--> $DIR/illformed.rs:34:1
|
LL | struct MultipleFieldsStructWithElementCount {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: scalable vectors cannot have multiple fields
--> $DIR/illformed.rs:42:1
|
LL | struct MultipleFieldsTupleWithElementCount(f32, u32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: scalable vector structs can only have scalable vector fields
--> $DIR/illformed.rs:48:5
|
LL | _ty: f32,
| ^^^^^^^^
error: scalable vector structs can only have scalable vector fields
--> $DIR/illformed.rs:54:47
|
LL | struct MultipleFieldsTupleWithoutElementCount(f32, u32);
| ^^^
error: aborting due to 17 previous errors

View file

@ -0,0 +1,163 @@
//@ edition: 2024
#![allow(internal_features, unused_imports, unused_macros)]
#![feature(extern_types)]
#![feature(gen_blocks)]
#![feature(rustc_attrs)]
#![feature(stmt_expr_attributes)]
#![feature(trait_alias)]
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on extern crates
extern crate std as other_std;
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on use statements
use std::vec::Vec;
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on statics
static _X: u32 = 0;
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on constants
const _Y: u32 = 0;
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on modules
mod bar {
}
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on foreign modules
unsafe extern "C" {
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on foreign statics
static X: &'static u32;
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on foreign types
type Y;
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on foreign functions
fn foo();
}
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on type aliases
type Foo = u32;
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on enums
enum Bar<#[rustc_scalable_vector(4)] T> {
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on function params
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on enum variants
Baz(std::marker::PhantomData<T>),
}
struct Qux {
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on struct fields
field: u32,
}
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on unions
union FooBar {
x: u32,
y: u32,
}
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on traits
trait FooBaz {
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on associated types
type Foo;
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on associated consts
const Bar: i32;
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on provided trait methods
fn foo() {}
}
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on trait aliases
trait FooQux = FooBaz;
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on inherent impl blocks
impl<T> Bar<T> {
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on inherent methods
fn foo() {}
}
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on trait impl blocks
impl<T> FooBaz for Bar<T> {
type Foo = u32;
const Bar: i32 = 3;
}
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on macro defs
macro_rules! barqux { ($foo:tt) => { $foo }; }
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on functions
fn barqux(#[rustc_scalable_vector(4)] _x: u32) {}
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on function params
//~^^ ERROR: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on functions
async fn async_foo() {}
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on functions
gen fn gen_foo() {}
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on functions
async gen fn async_gen_foo() {}
fn main() {
let _x = #[rustc_scalable_vector(4)] || { };
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on closures
let _y = #[rustc_scalable_vector(4)] 3 + 4;
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on expressions
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on statements
let _z = 3;
match _z {
#[rustc_scalable_vector(4)]
//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on match arms
1 => (),
_ => (),
}
}
#[rustc_scalable_vector("4")]
//~^ ERROR: malformed `rustc_scalable_vector` attribute input
struct ArgNotLit(f32);
#[rustc_scalable_vector(4, 2)]
//~^ ERROR: malformed `rustc_scalable_vector` attribute input
struct ArgMultipleLits(f32);
#[rustc_scalable_vector(count = "4")]
//~^ ERROR: malformed `rustc_scalable_vector` attribute input
struct ArgKind(f32);
#[rustc_scalable_vector(65536)]
//~^ ERROR: element count in `rustc_scalable_vector` is too large: `65536`
struct CountTooLarge(f32);
#[rustc_scalable_vector(4)]
struct Okay(f32);
#[rustc_scalable_vector]
struct OkayNoArg(f32);
//~^ ERROR: scalable vector structs can only have scalable vector fields

View file

@ -0,0 +1,339 @@
error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
--> $DIR/invalid.rs:109:11
|
LL | fn barqux(#[rustc_scalable_vector(4)] _x: u32) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `#[rustc_scalable_vector]` attribute cannot be used on extern crates
--> $DIR/invalid.rs:9:1
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on use statements
--> $DIR/invalid.rs:13:1
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on statics
--> $DIR/invalid.rs:17:1
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on constants
--> $DIR/invalid.rs:21:1
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on modules
--> $DIR/invalid.rs:25:1
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on foreign modules
--> $DIR/invalid.rs:30:1
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on foreign statics
--> $DIR/invalid.rs:33:5
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on foreign types
--> $DIR/invalid.rs:36:5
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on foreign functions
--> $DIR/invalid.rs:39:5
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on type aliases
--> $DIR/invalid.rs:44:1
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on enums
--> $DIR/invalid.rs:48:1
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on function params
--> $DIR/invalid.rs:50:10
|
LL | enum Bar<#[rustc_scalable_vector(4)] T> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on enum variants
--> $DIR/invalid.rs:52:5
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on struct fields
--> $DIR/invalid.rs:58:5
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on unions
--> $DIR/invalid.rs:63:1
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on traits
--> $DIR/invalid.rs:70:1
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on associated types
--> $DIR/invalid.rs:73:5
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on associated consts
--> $DIR/invalid.rs:76:5
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on provided trait methods
--> $DIR/invalid.rs:79:5
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on trait aliases
--> $DIR/invalid.rs:84:1
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on inherent impl blocks
--> $DIR/invalid.rs:88:1
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on inherent methods
--> $DIR/invalid.rs:91:5
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on trait impl blocks
--> $DIR/invalid.rs:96:1
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on macro defs
--> $DIR/invalid.rs:103:1
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on functions
--> $DIR/invalid.rs:107:1
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on function params
--> $DIR/invalid.rs:109:11
|
LL | fn barqux(#[rustc_scalable_vector(4)] _x: u32) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on functions
--> $DIR/invalid.rs:113:1
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on functions
--> $DIR/invalid.rs:117:1
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on functions
--> $DIR/invalid.rs:121:1
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on closures
--> $DIR/invalid.rs:126:14
|
LL | let _x = #[rustc_scalable_vector(4)] || { };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on expressions
--> $DIR/invalid.rs:128:14
|
LL | let _y = #[rustc_scalable_vector(4)] 3 + 4;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on statements
--> $DIR/invalid.rs:130:5
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error: `#[rustc_scalable_vector]` attribute cannot be used on match arms
--> $DIR/invalid.rs:135:9
|
LL | #[rustc_scalable_vector(4)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_scalable_vector]` can only be applied to structs
error[E0539]: malformed `rustc_scalable_vector` attribute input
--> $DIR/invalid.rs:142:1
|
LL | #[rustc_scalable_vector("4")]
| ^^^^^^^^^^^^^^^^^^^^^^^^---^^
| |
| expected an integer literal here
|
help: try changing it to one of the following valid forms of the attribute
|
LL - #[rustc_scalable_vector("4")]
LL + #[rustc_scalable_vector(count)]
|
LL - #[rustc_scalable_vector("4")]
LL + #[rustc_scalable_vector]
|
error[E0805]: malformed `rustc_scalable_vector` attribute input
--> $DIR/invalid.rs:146:1
|
LL | #[rustc_scalable_vector(4, 2)]
| ^^^^^^^^^^^^^^^^^^^^^^^------^
| |
| expected a single argument here
|
help: try changing it to one of the following valid forms of the attribute
|
LL - #[rustc_scalable_vector(4, 2)]
LL + #[rustc_scalable_vector(count)]
|
LL - #[rustc_scalable_vector(4, 2)]
LL + #[rustc_scalable_vector]
|
error[E0539]: malformed `rustc_scalable_vector` attribute input
--> $DIR/invalid.rs:150:1
|
LL | #[rustc_scalable_vector(count = "4")]
| ^^^^^^^^^^^^^^^^^^^^^^^^-----------^^
| |
| expected an integer literal here
|
help: try changing it to one of the following valid forms of the attribute
|
LL - #[rustc_scalable_vector(count = "4")]
LL + #[rustc_scalable_vector(count)]
|
LL - #[rustc_scalable_vector(count = "4")]
LL + #[rustc_scalable_vector]
|
error: element count in `rustc_scalable_vector` is too large: `65536`
--> $DIR/invalid.rs:154:1
|
LL | #[rustc_scalable_vector(65536)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the value may not exceed `u16::MAX`
error: scalable vector structs can only have scalable vector fields
--> $DIR/invalid.rs:162:18
|
LL | struct OkayNoArg(f32);
| ^^^
error: aborting due to 39 previous errors
Some errors have detailed explanations: E0539, E0805.
For more information about an error, try `rustc --explain E0539`.

View file

@ -0,0 +1,40 @@
//@ build-fail
//@ compile-flags: --crate-type=lib
//@ only-aarch64
#![allow(incomplete_features, internal_features)]
#![feature(
simd_ffi,
rustc_attrs,
link_llvm_intrinsics
)]
#[derive(Copy, Clone)]
#[rustc_scalable_vector(4)]
#[allow(non_camel_case_types)]
pub struct svint32_t(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;
//~^ WARN: `extern` block uses type `svint32_t`, which is not FFI-safe
}
unsafe { _svdup_n_s32(op) }
}
pub fn non_annotated_callee(x: svint32_t) {}
//~^ ERROR: this function definition uses scalable vector type `svint32_t`
#[target_feature(enable = "sve")]
pub fn annotated_callee(x: svint32_t) {} // okay!
#[target_feature(enable = "sve")]
pub fn caller() {
unsafe {
let a = svdup_n_s32(42);
non_annotated_callee(a);
annotated_callee(a);
}
}

View file

@ -0,0 +1,25 @@
warning: `extern` block uses type `svint32_t`, which is not FFI-safe
--> $DIR/require-target-feature.rs:21:37
|
LL | fn _svdup_n_s32(op: i32) -> svint32_t;
| ^^^^^^^^^ not FFI-safe
|
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
= note: this struct has unspecified layout
note: the type is defined here
--> $DIR/require-target-feature.rs:14:1
|
LL | pub struct svint32_t(i32);
| ^^^^^^^^^^^^^^^^^^^^
= note: `#[warn(improper_ctypes)]` on by default
error: this function definition uses scalable vector type `svint32_t` which (with the chosen ABI) requires the `sve` target feature, which is not enabled
--> $DIR/require-target-feature.rs:27:1
|
LL | pub fn non_annotated_callee(x: svint32_t) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
= help: consider enabling it globally (`-C target-feature=+sve`) or locally (`#[target_feature(enable="sve")]`)
error: aborting due to 1 previous error; 1 warning emitted

View file

@ -0,0 +1,37 @@
//@ build-pass
//@ compile-flags: --crate-type=lib
//@ only-aarch64
#![allow(internal_features)]
#![feature(
link_llvm_intrinsics,
rustc_attrs,
simd_ffi,
)]
#[derive(Copy, Clone)]
#[rustc_scalable_vector(4)]
#[allow(non_camel_case_types)]
pub struct svint32_t(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;
//~^ WARN: `extern` block uses type `svint32_t`, which is not FFI-safe
}
unsafe { _svdup_n_s32(op) }
}
// Tests that scalable vectors can be locals, arguments and return types.
#[target_feature(enable = "sve")]
fn id(v: svint32_t) -> svint32_t { v }
#[target_feature(enable = "sve")]
fn foo() {
unsafe {
let v = svdup_n_s32(1);
let v = id(v);
}
}

View file

@ -0,0 +1,17 @@
warning: `extern` block uses type `svint32_t`, which is not FFI-safe
--> $DIR/value-type.rs:20:37
|
LL | fn _svdup_n_s32(op: i32) -> svint32_t;
| ^^^^^^^^^ not FFI-safe
|
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
= note: this struct has unspecified layout
note: the type is defined here
--> $DIR/value-type.rs:14:1
|
LL | pub struct svint32_t(i32);
| ^^^^^^^^^^^^^^^^^^^^
= note: `#[warn(improper_ctypes)]` on by default
warning: 1 warning emitted

View file

@ -0,0 +1,10 @@
//@ check-pass
//@ compile-flags: --crate-type=lib
#![feature(rustc_attrs)]
#[rustc_scalable_vector(16)]
struct ScalableU8(u8);
fn main() {
let x: [ScalableU8; 4] = todo!();
}

View file

@ -0,0 +1,48 @@
//@ check-pass
//@ compile-flags: --crate-type=lib
#![feature(rustc_attrs)]
#[rustc_scalable_vector(16)]
struct ScalableU8(u8);
#[rustc_scalable_vector(8)]
struct ScalableU16(u16);
#[rustc_scalable_vector(4)]
struct ScalableU32(u32);
#[rustc_scalable_vector(2)]
struct ScalableU64(u64);
#[rustc_scalable_vector(1)]
struct ScalableU128(u128);
#[rustc_scalable_vector(16)]
struct ScalableI8(i8);
#[rustc_scalable_vector(8)]
struct ScalableI16(i16);
#[rustc_scalable_vector(4)]
struct ScalableI32(i32);
#[rustc_scalable_vector(2)]
struct ScalableI64(i64);
#[rustc_scalable_vector(1)]
struct ScalableI128(i128);
#[rustc_scalable_vector(8)]
struct ScalableF16(f32);
#[rustc_scalable_vector(4)]
struct ScalableF32(f32);
#[rustc_scalable_vector(2)]
struct ScalableF64(f64);
#[rustc_scalable_vector(16)]
struct ScalableBool(bool);
#[rustc_scalable_vector]
struct ScalableTuple(ScalableU8, ScalableU8, ScalableU8);

View file

@ -95,7 +95,7 @@ body:
did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo)
variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }]
flags: IS_ENUM
repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 13397682652773712997 }
repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 13397682652773712997 }
args: []
variant_index: 0
subpatterns: [
@ -109,7 +109,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: 7908585036048874241 }
repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 7908585036048874241 }
args: []
variant_index: 0
subpatterns: []
@ -157,7 +157,7 @@ body:
did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo)
variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }]
flags: IS_ENUM
repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 13397682652773712997 }
repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 13397682652773712997 }
args: []
variant_index: 0
subpatterns: [
@ -209,7 +209,7 @@ body:
did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo)
variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }]
flags: IS_ENUM
repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 13397682652773712997 }
repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 13397682652773712997 }
args: []
variant_index: 1
subpatterns: []