Skip to content

Commit 95a27ad

Browse files
committed
Auto merge of rust-lang#143924 - davidtwco:sve-infrastructure, r=workingjubilee
`rustc_scalable_vector(N)` Supercedes rust-lang#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#145052 for request for a lang experiment.
2 parents 61cc47e + f0dfeab commit 95a27ad

File tree

84 files changed

+2232
-144
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+2232
-144
lines changed

compiler/rustc_abi/src/callconv.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
6060
/// This is public so that it can be used in unit tests, but
6161
/// should generally only be relevant to the ABI details of
6262
/// specific targets.
63+
#[tracing::instrument(skip(cx), level = "debug")]
6364
pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, Heterogeneous>
6465
where
6566
Ty: TyAbiInterface<'a, C> + Copy,
@@ -82,6 +83,10 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
8283
}))
8384
}
8485

86+
BackendRepr::ScalableVector { .. } => {
87+
unreachable!("`homogeneous_aggregate` should not be called for scalable vectors")
88+
}
89+
8590
BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => {
8691
// Helper for computing `homogeneous_aggregate`, allowing a custom
8792
// starting offset (used below for handling variants).

compiler/rustc_abi/src/layout.rs

Lines changed: 87 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use tracing::{debug, trace};
1111
use crate::{
1212
AbiAlign, Align, BackendRepr, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer,
1313
LayoutData, Niche, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding,
14-
Variants, WrappingRange,
14+
TargetDataLayout, Variants, WrappingRange,
1515
};
1616

1717
mod coroutine;
@@ -143,58 +143,32 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
143143
})
144144
}
145145

146-
pub fn simd_type<
146+
pub fn scalable_vector_type<FieldIdx, VariantIdx, F>(
147+
&self,
148+
element: F,
149+
count: u64,
150+
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F>
151+
where
147152
FieldIdx: Idx,
148153
VariantIdx: Idx,
149154
F: AsRef<LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
150-
>(
155+
{
156+
vector_type_layout(VectorKind::Scalable, self.cx.data_layout(), element, count)
157+
}
158+
159+
pub fn simd_type<FieldIdx, VariantIdx, F>(
151160
&self,
152161
element: F,
153162
count: u64,
154163
repr_packed: bool,
155-
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
156-
let elt = element.as_ref();
157-
if count == 0 {
158-
return Err(LayoutCalculatorError::ZeroLengthSimdType);
159-
} else if count > crate::MAX_SIMD_LANES {
160-
return Err(LayoutCalculatorError::OversizedSimdType {
161-
max_lanes: crate::MAX_SIMD_LANES,
162-
});
163-
}
164-
165-
let BackendRepr::Scalar(e_repr) = elt.backend_repr else {
166-
return Err(LayoutCalculatorError::NonPrimitiveSimdType(element));
167-
};
168-
169-
// Compute the size and alignment of the vector
170-
let dl = self.cx.data_layout();
171-
let size =
172-
elt.size.checked_mul(count, dl).ok_or_else(|| LayoutCalculatorError::SizeOverflow)?;
173-
let (repr, align) = if repr_packed && !count.is_power_of_two() {
174-
// Non-power-of-two vectors have padding up to the next power-of-two.
175-
// If we're a packed repr, remove the padding while keeping the alignment as close
176-
// to a vector as possible.
177-
(BackendRepr::Memory { sized: true }, Align::max_aligned_factor(size))
178-
} else {
179-
(BackendRepr::SimdVector { element: e_repr, count }, dl.llvmlike_vector_align(size))
180-
};
181-
let size = size.align_to(align);
182-
183-
Ok(LayoutData {
184-
variants: Variants::Single { index: VariantIdx::new(0) },
185-
fields: FieldsShape::Arbitrary {
186-
offsets: [Size::ZERO].into(),
187-
memory_index: [0].into(),
188-
},
189-
backend_repr: repr,
190-
largest_niche: elt.largest_niche,
191-
uninhabited: false,
192-
size,
193-
align: AbiAlign::new(align),
194-
max_repr_align: None,
195-
unadjusted_abi_align: elt.align.abi,
196-
randomization_seed: elt.randomization_seed.wrapping_add(Hash64::new(count)),
197-
})
164+
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F>
165+
where
166+
FieldIdx: Idx,
167+
VariantIdx: Idx,
168+
F: AsRef<LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
169+
{
170+
let kind = if repr_packed { VectorKind::PackedFixed } else { VectorKind::Fixed };
171+
vector_type_layout(kind, self.cx.data_layout(), element, count)
198172
}
199173

200174
/// Compute the layout for a coroutine.
@@ -453,6 +427,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
453427
BackendRepr::Scalar(..)
454428
| BackendRepr::ScalarPair(..)
455429
| BackendRepr::SimdVector { .. }
430+
| BackendRepr::ScalableVector { .. }
456431
| BackendRepr::Memory { .. } => repr,
457432
},
458433
};
@@ -524,7 +499,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
524499
hide_niches(a);
525500
hide_niches(b);
526501
}
527-
BackendRepr::SimdVector { element, count: _ } => hide_niches(element),
502+
BackendRepr::SimdVector { element, .. }
503+
| BackendRepr::ScalableVector { element, .. } => hide_niches(element),
528504
BackendRepr::Memory { sized: _ } => {}
529505
}
530506
st.largest_niche = None;
@@ -1501,3 +1477,67 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
15011477
s
15021478
}
15031479
}
1480+
1481+
enum VectorKind {
1482+
/// `#[rustc_scalable_vector]`
1483+
Scalable,
1484+
/// `#[repr(simd, packed)]`
1485+
PackedFixed,
1486+
/// `#[repr(simd)]`
1487+
Fixed,
1488+
}
1489+
1490+
fn vector_type_layout<FieldIdx, VariantIdx, F>(
1491+
kind: VectorKind,
1492+
dl: &TargetDataLayout,
1493+
element: F,
1494+
count: u64,
1495+
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F>
1496+
where
1497+
FieldIdx: Idx,
1498+
VariantIdx: Idx,
1499+
F: AsRef<LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
1500+
{
1501+
let elt = element.as_ref();
1502+
if count == 0 {
1503+
return Err(LayoutCalculatorError::ZeroLengthSimdType);
1504+
} else if count > crate::MAX_SIMD_LANES {
1505+
return Err(LayoutCalculatorError::OversizedSimdType { max_lanes: crate::MAX_SIMD_LANES });
1506+
}
1507+
1508+
let BackendRepr::Scalar(element) = elt.backend_repr else {
1509+
return Err(LayoutCalculatorError::NonPrimitiveSimdType(element));
1510+
};
1511+
1512+
// Compute the size and alignment of the vector
1513+
let size =
1514+
elt.size.checked_mul(count, dl).ok_or_else(|| LayoutCalculatorError::SizeOverflow)?;
1515+
let (repr, align) = match kind {
1516+
VectorKind::Scalable => {
1517+
(BackendRepr::ScalableVector { element, count }, dl.llvmlike_vector_align(size))
1518+
}
1519+
// Non-power-of-two vectors have padding up to the next power-of-two.
1520+
// If we're a packed repr, remove the padding while keeping the alignment as close
1521+
// to a vector as possible.
1522+
VectorKind::PackedFixed if !count.is_power_of_two() => {
1523+
(BackendRepr::Memory { sized: true }, Align::max_aligned_factor(size))
1524+
}
1525+
VectorKind::PackedFixed | VectorKind::Fixed => {
1526+
(BackendRepr::SimdVector { element, count }, dl.llvmlike_vector_align(size))
1527+
}
1528+
};
1529+
let size = size.align_to(align);
1530+
1531+
Ok(LayoutData {
1532+
variants: Variants::Single { index: VariantIdx::new(0) },
1533+
fields: FieldsShape::Arbitrary { offsets: [Size::ZERO].into(), memory_index: [0].into() },
1534+
backend_repr: repr,
1535+
largest_niche: elt.largest_niche,
1536+
uninhabited: false,
1537+
size,
1538+
align: AbiAlign::new(align),
1539+
max_repr_align: None,
1540+
unadjusted_abi_align: elt.align.abi,
1541+
randomization_seed: elt.randomization_seed.wrapping_add(Hash64::new(count)),
1542+
})
1543+
}

compiler/rustc_abi/src/layout/ty.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ impl<'a, Ty> AsRef<LayoutData<FieldIdx, VariantIdx>> for TyAndLayout<'a, Ty> {
155155

156156
/// Trait that needs to be implemented by the higher-level type representation
157157
/// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality.
158-
pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug {
158+
pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug + std::fmt::Display {
159159
fn ty_and_layout_for_variant(
160160
this: TyAndLayout<'a, Self>,
161161
cx: &C,
@@ -172,6 +172,7 @@ pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug {
172172
fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
173173
fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
174174
fn is_transparent(this: TyAndLayout<'a, Self>) -> bool;
175+
fn is_scalable_vector(this: TyAndLayout<'a, Self>) -> bool;
175176
/// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
176177
fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'a, Self>) -> bool;
177178
}
@@ -271,6 +272,13 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
271272
Ty::is_transparent(self)
272273
}
273274

275+
pub fn is_scalable_vector<C>(self) -> bool
276+
where
277+
Ty: TyAbiInterface<'a, C>,
278+
{
279+
Ty::is_scalable_vector(self)
280+
}
281+
274282
/// If this method returns `true`, then this type should always have a `PassMode` of
275283
/// `Indirect { on_stack: false, .. }` when being used as the argument type of a function with a
276284
/// non-Rustic ABI (this is true for structs annotated with the

compiler/rustc_abi/src/lib.rs

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,11 @@ bitflags! {
9696
/// If true, the type is always passed indirectly by non-Rustic ABIs.
9797
/// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
9898
const PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS = 1 << 5;
99-
/// Any of these flags being set prevent field reordering optimisation.
100-
const FIELD_ORDER_UNOPTIMIZABLE = ReprFlags::IS_C.bits()
99+
const IS_SCALABLE = 1 << 6;
100+
// Any of these flags being set prevent field reordering optimisation.
101+
const FIELD_ORDER_UNOPTIMIZABLE = ReprFlags::IS_C.bits()
101102
| ReprFlags::IS_SIMD.bits()
103+
| ReprFlags::IS_SCALABLE.bits()
102104
| ReprFlags::IS_LINEAR.bits();
103105
const ABI_UNOPTIMIZABLE = ReprFlags::IS_C.bits() | ReprFlags::IS_SIMD.bits();
104106
}
@@ -135,6 +137,19 @@ impl IntegerType {
135137
}
136138
}
137139

140+
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
141+
#[cfg_attr(
142+
feature = "nightly",
143+
derive(Encodable_NoContext, Decodable_NoContext, HashStable_Generic)
144+
)]
145+
pub enum ScalableElt {
146+
/// `N` in `rustc_scalable_vector(N)` - the element count of the scalable vector
147+
ElementCount(u16),
148+
/// `rustc_scalable_vector` w/out `N`, used for tuple types of scalable vectors that only
149+
/// contain other scalable vectors
150+
Container,
151+
}
152+
138153
/// Represents the repr options provided by the user.
139154
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
140155
#[cfg_attr(
@@ -146,6 +161,8 @@ pub struct ReprOptions {
146161
pub align: Option<Align>,
147162
pub pack: Option<Align>,
148163
pub flags: ReprFlags,
164+
/// `#[rustc_scalable_vector]`
165+
pub scalable: Option<ScalableElt>,
149166
/// The seed to be used for randomizing a type's layout
150167
///
151168
/// Note: This could technically be a `u128` which would
@@ -162,6 +179,11 @@ impl ReprOptions {
162179
self.flags.contains(ReprFlags::IS_SIMD)
163180
}
164181

182+
#[inline]
183+
pub fn scalable(&self) -> bool {
184+
self.flags.contains(ReprFlags::IS_SCALABLE)
185+
}
186+
165187
#[inline]
166188
pub fn c(&self) -> bool {
167189
self.flags.contains(ReprFlags::IS_C)
@@ -1736,6 +1758,10 @@ impl AddressSpace {
17361758
pub enum BackendRepr {
17371759
Scalar(Scalar),
17381760
ScalarPair(Scalar, Scalar),
1761+
ScalableVector {
1762+
element: Scalar,
1763+
count: u64,
1764+
},
17391765
SimdVector {
17401766
element: Scalar,
17411767
count: u64,
@@ -1754,6 +1780,12 @@ impl BackendRepr {
17541780
match *self {
17551781
BackendRepr::Scalar(_)
17561782
| BackendRepr::ScalarPair(..)
1783+
// FIXME(rustc_scalable_vector): Scalable vectors are `Sized` while the
1784+
// `sized_hierarchy` feature is not yet fully implemented. After `sized_hierarchy` is
1785+
// fully implemented, scalable vectors will remain `Sized`, they just won't be
1786+
// `const Sized` - whether `is_unsized` continues to return `false` at that point will
1787+
// need to be revisited and will depend on what `is_unsized` is used for.
1788+
| BackendRepr::ScalableVector { .. }
17571789
| BackendRepr::SimdVector { .. } => false,
17581790
BackendRepr::Memory { sized } => !sized,
17591791
}
@@ -1794,7 +1826,9 @@ impl BackendRepr {
17941826
BackendRepr::Scalar(s) => Some(s.align(cx).abi),
17951827
BackendRepr::ScalarPair(s1, s2) => Some(s1.align(cx).max(s2.align(cx)).abi),
17961828
// The align of a Vector can vary in surprising ways
1797-
BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => None,
1829+
BackendRepr::SimdVector { .. }
1830+
| BackendRepr::Memory { .. }
1831+
| BackendRepr::ScalableVector { .. } => None,
17981832
}
17991833
}
18001834

@@ -1816,7 +1850,9 @@ impl BackendRepr {
18161850
Some(size)
18171851
}
18181852
// The size of a Vector can vary in surprising ways
1819-
BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => None,
1853+
BackendRepr::SimdVector { .. }
1854+
| BackendRepr::Memory { .. }
1855+
| BackendRepr::ScalableVector { .. } => None,
18201856
}
18211857
}
18221858

@@ -1831,6 +1867,9 @@ impl BackendRepr {
18311867
BackendRepr::SimdVector { element: element.to_union(), count }
18321868
}
18331869
BackendRepr::Memory { .. } => BackendRepr::Memory { sized: true },
1870+
BackendRepr::ScalableVector { element, count } => {
1871+
BackendRepr::ScalableVector { element: element.to_union(), count }
1872+
}
18341873
}
18351874
}
18361875

@@ -2071,7 +2110,9 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
20712110
/// Returns `true` if this is an aggregate type (including a ScalarPair!)
20722111
pub fn is_aggregate(&self) -> bool {
20732112
match self.backend_repr {
2074-
BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => false,
2113+
BackendRepr::Scalar(_)
2114+
| BackendRepr::SimdVector { .. }
2115+
| BackendRepr::ScalableVector { .. } => false,
20752116
BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => true,
20762117
}
20772118
}
@@ -2165,6 +2206,19 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
21652206
self.is_sized() && self.size.bytes() == 0 && self.align.bytes() == 1
21662207
}
21672208

2209+
/// Returns `true` if the size of the type is only known at runtime.
2210+
pub fn is_runtime_sized(&self) -> bool {
2211+
matches!(self.backend_repr, BackendRepr::ScalableVector { .. })
2212+
}
2213+
2214+
/// Returns the elements count of a scalable vector.
2215+
pub fn scalable_vector_element_count(&self) -> Option<u64> {
2216+
match self.backend_repr {
2217+
BackendRepr::ScalableVector { count, .. } => Some(count),
2218+
_ => None,
2219+
}
2220+
}
2221+
21682222
/// Returns `true` if the type is a ZST and not unsized.
21692223
///
21702224
/// 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> {
21732227
match self.backend_repr {
21742228
BackendRepr::Scalar(_)
21752229
| BackendRepr::ScalarPair(..)
2230+
| BackendRepr::ScalableVector { .. }
21762231
| BackendRepr::SimdVector { .. } => false,
21772232
BackendRepr::Memory { sized } => sized && self.size.bytes() == 0,
21782233
}

compiler/rustc_ast_passes/messages.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,8 @@ ast_passes_precise_capturing_duplicated = duplicate `use<...>` precise capturing
270270
271271
ast_passes_precise_capturing_not_allowed_here = `use<...>` precise capturing syntax not allowed in {$loc}
272272
273+
ast_passes_scalable_vector_not_tuple_struct = scalable vectors must be tuple structs
274+
273275
ast_passes_static_without_body =
274276
free static item without body
275277
.suggestion = provide a definition for the static

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,6 +1319,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
13191319
}
13201320
ItemKind::Struct(ident, generics, vdata) => {
13211321
self.with_tilde_const(Some(TildeConstReason::Struct { span: item.span }), |this| {
1322+
// Scalable vectors can only be tuple structs
1323+
let is_scalable_vector =
1324+
item.attrs.iter().any(|attr| attr.has_name(sym::rustc_scalable_vector));
1325+
if is_scalable_vector && !matches!(vdata, VariantData::Tuple(..)) {
1326+
this.dcx()
1327+
.emit_err(errors::ScalableVectorNotTupleStruct { span: item.span });
1328+
}
1329+
13221330
match vdata {
13231331
VariantData::Struct { fields, .. } => {
13241332
this.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);

0 commit comments

Comments
 (0)