Skip to content

Commit 78b0605

Browse files
attr: parse rustc_scalable_vector(N)
Extend parsing of `ReprOptions` with `rustc_scalable_vector(N)` which optionally accepts a single literal integral value - the base multiple of lanes that are in a scalable vector. Can only be applied to structs. Co-authored-by: Jamie Cunliffe <Jamie.Cunliffe@arm.com>
1 parent 6e7dd2c commit 78b0605

File tree

16 files changed

+620
-9
lines changed

16 files changed

+620
-9
lines changed

compiler/rustc_abi/src/lib.rs

Lines changed: 24 additions & 2 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)

compiler/rustc_attr_parsing/messages.ftl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,9 @@ attr_parsing_rustc_allowed_unstable_pairing =
200200
attr_parsing_rustc_promotable_pairing =
201201
`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute
202202
203+
attr_parsing_rustc_scalable_vector_count_out_of_range = element count in `rustc_scalable_vector` is too large: `{$n}`
204+
.note = the value may not exceed `u16::MAX`
205+
203206
attr_parsing_soft_no_args =
204207
`soft` should not have any arguments
205208

compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::prelude::*;
22
use super::util::parse_single_integer;
3+
use crate::session_diagnostics::RustcScalableVectorCountOutOfRange;
34

45
pub(crate) struct RustcMainParser;
56

@@ -76,3 +77,29 @@ impl<S: Stage> SingleAttributeParser<S> for RustcSimdMonomorphizeLaneLimitParser
7677
Some(AttributeKind::RustcSimdMonomorphizeLaneLimit(cx.parse_limit_int(nv)?))
7778
}
7879
}
80+
81+
pub(crate) struct RustcScalableVectorParser;
82+
83+
impl<S: Stage> SingleAttributeParser<S> for RustcScalableVectorParser {
84+
const PATH: &[rustc_span::Symbol] = &[sym::rustc_scalable_vector];
85+
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
86+
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
87+
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
88+
const TEMPLATE: AttributeTemplate = template!(Word, List: &["count"]);
89+
90+
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
91+
if args.no_args().is_ok() {
92+
return Some(AttributeKind::RustcScalableVector {
93+
element_count: None,
94+
span: cx.attr_span,
95+
});
96+
}
97+
98+
let n = parse_single_integer(cx, args)?;
99+
let Ok(n) = n.try_into() else {
100+
cx.emit_err(RustcScalableVectorCountOutOfRange { span: cx.attr_span, n });
101+
return None;
102+
};
103+
Some(AttributeKind::RustcScalableVector { element_count: Some(n), span: cx.attr_span })
104+
}
105+
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ use crate::attributes::prototype::CustomMirParser;
6060
use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser};
6161
use crate::attributes::rustc_internal::{
6262
RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, RustcMainParser,
63-
RustcObjectLifetimeDefaultParser, RustcSimdMonomorphizeLaneLimitParser,
63+
RustcObjectLifetimeDefaultParser, RustcScalableVectorParser,
64+
RustcSimdMonomorphizeLaneLimitParser,
6465
};
6566
use crate::attributes::semantics::MayDangleParser;
6667
use crate::attributes::stability::{
@@ -209,6 +210,7 @@ attribute_parsers!(
209210
Single<RustcLayoutScalarValidRangeEndParser>,
210211
Single<RustcLayoutScalarValidRangeStartParser>,
211212
Single<RustcObjectLifetimeDefaultParser>,
213+
Single<RustcScalableVectorParser>,
212214
Single<RustcSimdMonomorphizeLaneLimitParser>,
213215
Single<SanitizeParser>,
214216
Single<ShouldPanicParser>,

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,15 @@ pub(crate) struct LinkOrdinalOutOfRange {
501501
pub ordinal: u128,
502502
}
503503

504+
#[derive(Diagnostic)]
505+
#[diag(attr_parsing_rustc_scalable_vector_count_out_of_range)]
506+
#[note]
507+
pub(crate) struct RustcScalableVectorCountOutOfRange {
508+
#[primary_span]
509+
pub span: Span,
510+
pub n: u128,
511+
}
512+
504513
pub(crate) enum AttributeParseErrorReason<'a> {
505514
ExpectedNoArgs,
506515
ExpectedStringLiteral {

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1422,6 +1422,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
14221422
rustc_force_inline, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, EncodeCrossCrate::Yes,
14231423
"`#[rustc_force_inline]` forces a free function to be inlined"
14241424
),
1425+
rustc_attr!(
1426+
rustc_scalable_vector, Normal, template!(List: &["count"]), WarnFollowing, EncodeCrossCrate::Yes,
1427+
"`#[rustc_scalable_vector]` defines a scalable vector type"
1428+
),
14251429

14261430
// ==========================================================================
14271431
// Internal attributes, Testing:

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,14 @@ pub enum AttributeKind {
878878
/// Represents `#[rustc_pass_indirectly_in_non_rustic_abis]`
879879
RustcPassIndirectlyInNonRusticAbis(Span),
880880

881+
/// Represents `#[rustc_scalable_vector(N)]`
882+
RustcScalableVector {
883+
/// The base multiple of lanes that are in a scalable vector, if provided. `element_count`
884+
/// is not provided for representing tuple types.
885+
element_count: Option<u16>,
886+
span: Span,
887+
},
888+
881889
/// Represents `#[rustc_should_not_be_called_on_const_items]`
882890
RustcShouldNotBeCalledOnConstItems(Span),
883891

compiler/rustc_hir/src/attrs/encode_cross_crate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ impl AttributeKind {
9595
RustcMain => No,
9696
RustcObjectLifetimeDefault => No,
9797
RustcPassIndirectlyInNonRusticAbis(..) => No,
98+
RustcScalableVector { .. } => Yes,
9899
RustcShouldNotBeCalledOnConstItems(..) => Yes,
99100
RustcSimdMonomorphizeLaneLimit(..) => Yes, // Affects layout computation, which needs to work cross-crate
100101
Sanitize { .. } => No,

compiler/rustc_hir/src/attrs/pretty_printing.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::num::NonZero;
2+
use std::ops::Deref;
23

34
use rustc_abi::Align;
45
use rustc_ast::token::{CommentKind, DocFragmentKind};
@@ -37,6 +38,15 @@ impl<T: PrintAttribute> PrintAttribute for &T {
3738
T::print_attribute(self, p)
3839
}
3940
}
41+
impl<T: PrintAttribute> PrintAttribute for Box<T> {
42+
fn should_render(&self) -> bool {
43+
self.deref().should_render()
44+
}
45+
46+
fn print_attribute(&self, p: &mut Printer) {
47+
T::print_attribute(self.deref(), p)
48+
}
49+
}
4050
impl<T: PrintAttribute> PrintAttribute for Option<T> {
4151
fn should_render(&self) -> bool {
4252
self.as_ref().is_some_and(|x| x.should_render())

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ pub use assoc::*;
2424
pub use generic_args::{GenericArgKind, TermKind, *};
2525
pub use generics::*;
2626
pub use intrinsic::IntrinsicDef;
27-
use rustc_abi::{Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, VariantIdx};
27+
use rustc_abi::{
28+
Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, ScalableElt, VariantIdx,
29+
};
2830
use rustc_ast::AttrVec;
2931
use rustc_ast::expand::typetree::{FncTree, Kind, Type, TypeTree};
3032
use rustc_ast::node_id::NodeMap;
@@ -1515,6 +1517,17 @@ impl<'tcx> TyCtxt<'tcx> {
15151517
}
15161518

15171519
let attributes = self.get_all_attrs(did);
1520+
let elt = find_attr!(
1521+
attributes,
1522+
AttributeKind::RustcScalableVector { element_count, .. } => element_count
1523+
)
1524+
.map(|elt| match elt {
1525+
Some(n) => ScalableElt::ElementCount(*n),
1526+
None => ScalableElt::Container,
1527+
});
1528+
if elt.is_some() {
1529+
flags.insert(ReprFlags::IS_SCALABLE);
1530+
}
15181531
if let Some(reprs) = find_attr!(attributes, AttributeKind::Repr { reprs, .. } => reprs) {
15191532
for (r, _) in reprs {
15201533
flags.insert(match *r {
@@ -1579,7 +1592,14 @@ impl<'tcx> TyCtxt<'tcx> {
15791592
flags.insert(ReprFlags::PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS);
15801593
}
15811594

1582-
ReprOptions { int: size, align: max_align, pack: min_pack, flags, field_shuffle_seed }
1595+
ReprOptions {
1596+
int: size,
1597+
align: max_align,
1598+
pack: min_pack,
1599+
flags,
1600+
field_shuffle_seed,
1601+
scalable: elt,
1602+
}
15831603
}
15841604

15851605
/// Look up the name of a definition across crates. This does not look at HIR.

0 commit comments

Comments
 (0)