Skip to content

Commit cfc2e38

Browse files
attr: parse repr(simd, scalable(N))
Extend parsing of `ReprOptions` with `repr(scalable(N))` which always accepts a single literal integral value - the base multiple of lanes that are in a scalable vector. Can only be applied to structs and must be used with `repr(simd)`. Co-authored-by: Jamie Cunliffe <Jamie.Cunliffe@arm.com>
1 parent 9e64506 commit cfc2e38

File tree

14 files changed

+1099
-8
lines changed

14 files changed

+1099
-8
lines changed

compiler/rustc_abi/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,11 @@ bitflags! {
9393
// Other flags can still inhibit reordering and thus randomization.
9494
// The seed stored in `ReprOptions.field_shuffle_seed`.
9595
const RANDOMIZE_LAYOUT = 1 << 4;
96+
const IS_SCALABLE = 1 << 5;
9697
// Any of these flags being set prevent field reordering optimisation.
9798
const FIELD_ORDER_UNOPTIMIZABLE = ReprFlags::IS_C.bits()
9899
| ReprFlags::IS_SIMD.bits()
100+
| ReprFlags::IS_SCALABLE.bits()
99101
| ReprFlags::IS_LINEAR.bits();
100102
const ABI_UNOPTIMIZABLE = ReprFlags::IS_C.bits() | ReprFlags::IS_SIMD.bits();
101103
}
@@ -143,6 +145,7 @@ pub struct ReprOptions {
143145
pub align: Option<Align>,
144146
pub pack: Option<Align>,
145147
pub flags: ReprFlags,
148+
pub scalable: Option<u32>,
146149
/// The seed to be used for randomizing a type's layout
147150
///
148151
/// Note: This could technically be a `u128` which would
@@ -159,6 +162,11 @@ impl ReprOptions {
159162
self.flags.contains(ReprFlags::IS_SIMD)
160163
}
161164

165+
#[inline]
166+
pub fn scalable(&self) -> bool {
167+
self.flags.contains(ReprFlags::IS_SCALABLE)
168+
}
169+
162170
#[inline]
163171
pub fn c(&self) -> bool {
164172
self.flags.contains(ReprFlags::IS_C)

compiler/rustc_attr_data_structures/src/attributes.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ pub enum ReprAttr {
6565
ReprC,
6666
ReprPacked(Align),
6767
ReprSimd,
68+
ReprScalable(ScalableElt),
6869
ReprTransparent,
6970
ReprAlign(Align),
7071
// this one is just so we can emit a lint for it
@@ -84,6 +85,13 @@ pub enum IntType {
8485
UnsignedInt(ast::UintTy),
8586
}
8687

88+
/// The base multiple of lanes that are in a scalable vector.
89+
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
90+
#[derive(Encodable, Decodable, HashStable_Generic, PrintAttribute)]
91+
pub struct ScalableElt {
92+
pub elt: u16,
93+
}
94+
8795
#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)]
8896
pub struct Deprecation {
8997
pub since: DeprecatedSince,

compiler/rustc_attr_parsing/messages.ftl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ attr_parsing_rustc_allowed_unstable_pairing =
110110
attr_parsing_rustc_promotable_pairing =
111111
`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute
112112
113+
attr_parsing_scalable_missing_n =
114+
invalid `scalable(num)` attribute: `scalable` needs an argument
115+
.suggestion = supply an argument here
116+
113117
attr_parsing_soft_no_args =
114118
`soft` should not have any arguments
115119

compiler/rustc_attr_parsing/src/attributes/repr.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use rustc_abi::Align;
22
use rustc_ast::{IntTy, LitIntType, LitKind, UintTy};
3-
use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr};
3+
use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr, ScalableElt};
44
use rustc_feature::{AttributeTemplate, template};
55
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
66

@@ -143,6 +143,11 @@ fn parse_repr<S: Stage>(
143143
(Some(sym::Rust), ArgParser::NoArgs) => Some(ReprRust),
144144
(Some(sym::C), ArgParser::NoArgs) => Some(ReprC),
145145
(Some(sym::simd), ArgParser::NoArgs) => Some(ReprSimd),
146+
(Some(sym::scalable), ArgParser::List(l)) => parse_repr_scalable(cx, l, param.span()),
147+
(Some(sym::scalable), ArgParser::NoArgs) => {
148+
cx.emit_err(session_diagnostics::ScalableAttrMissingN { span: param.span() });
149+
None
150+
}
146151
(Some(sym::transparent), ArgParser::NoArgs) => Some(ReprTransparent),
147152
(Some(name @ int_pat!()), ArgParser::NoArgs) => {
148153
// int_pat!() should make sure it always parses
@@ -321,3 +326,18 @@ impl<S: Stage> AttributeParser<S> for AlignParser {
321326
Some(AttributeKind::Align { align, span })
322327
}
323328
}
329+
330+
fn parse_repr_scalable<S: Stage>(
331+
cx: &AcceptContext<'_, '_, S>,
332+
list: &MetaItemListParser<'_>,
333+
span: Span,
334+
) -> Option<ReprAttr> {
335+
let Some(LitKind::Int(literal, LitIntType::Unsuffixed)) =
336+
list.single().and_then(|elt| elt.lit()).map(|lit| lit.kind)
337+
else {
338+
cx.emit_err(session_diagnostics::ScalableAttrMissingN { span });
339+
return None;
340+
};
341+
342+
literal.get().try_into().ok().map(|elt| ReprAttr::ReprScalable(ScalableElt { elt }))
343+
}

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,3 +628,11 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
628628
diag
629629
}
630630
}
631+
632+
#[derive(Diagnostic)]
633+
#[diag(attr_parsing_scalable_missing_n)]
634+
pub(crate) struct ScalableAttrMissingN {
635+
#[primary_span]
636+
#[suggestion(applicability = "has-placeholders", code = "scalable(...)")]
637+
pub span: Span,
638+
}

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1509,6 +1509,7 @@ impl<'tcx> TyCtxt<'tcx> {
15091509
let mut size = None;
15101510
let mut max_align: Option<Align> = None;
15111511
let mut min_pack: Option<Align> = None;
1512+
let mut elt: Option<u32> = None;
15121513

15131514
// Generate a deterministically-derived seed from the item's path hash
15141515
// to allow for cross-crate compilation to actually work
@@ -1537,6 +1538,10 @@ impl<'tcx> TyCtxt<'tcx> {
15371538
}
15381539
attr::ReprTransparent => ReprFlags::IS_TRANSPARENT,
15391540
attr::ReprSimd => ReprFlags::IS_SIMD,
1541+
attr::ReprScalable(e) => {
1542+
elt = Some(e.elt as u32);
1543+
ReprFlags::IS_SCALABLE
1544+
}
15401545
attr::ReprInt(i) => {
15411546
size = Some(match i {
15421547
attr::IntType::SignedInt(x) => match x {
@@ -1585,7 +1590,14 @@ impl<'tcx> TyCtxt<'tcx> {
15851590
flags.insert(ReprFlags::IS_LINEAR);
15861591
}
15871592

1588-
ReprOptions { int: size, align: max_align, pack: min_pack, flags, field_shuffle_seed }
1593+
ReprOptions {
1594+
int: size,
1595+
align: max_align,
1596+
pack: min_pack,
1597+
flags,
1598+
field_shuffle_seed,
1599+
scalable: elt,
1600+
}
15891601
}
15901602

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

compiler/rustc_middle/src/ty/sty.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,6 +1194,14 @@ impl<'tcx> Ty<'tcx> {
11941194
}
11951195
}
11961196

1197+
#[inline]
1198+
pub fn is_scalable_simd(self) -> bool {
1199+
match self.kind() {
1200+
Adt(def, _) => def.repr().simd() && def.repr().scalable(),
1201+
_ => false,
1202+
}
1203+
}
1204+
11971205
pub fn sequence_element_type(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
11981206
match self.kind() {
11991207
Array(ty, _) | Slice(ty) => *ty,

compiler/rustc_passes/messages.ftl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,9 @@ passes_repr_align_should_be_align =
601601
passes_repr_conflicting =
602602
conflicting representation hints
603603
604+
passes_repr_scalable_without_simd =
605+
`scalable` representation hint without `simd` representation hint
606+
604607
passes_rustc_allow_const_fn_unstable =
605608
attribute should be applied to `const fn`
606609
.label = not a `const fn`

compiler/rustc_passes/src/check_attr.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1927,6 +1927,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
19271927
let mut is_explicit_rust = false;
19281928
let mut is_c = false;
19291929
let mut is_simd = false;
1930+
let mut is_scalable = false;
19301931
let mut is_transparent = false;
19311932

19321933
for (repr, repr_span) in reprs {
@@ -1995,6 +1996,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
19951996
continue;
19961997
}
19971998
}
1999+
ReprAttr::ReprScalable(..) => {
2000+
is_scalable = true;
2001+
if target != Target::Struct {
2002+
self.dcx().emit_err(errors::AttrApplication::Struct {
2003+
hint_span: *repr_span,
2004+
span,
2005+
});
2006+
} else {
2007+
continue;
2008+
}
2009+
}
19982010
ReprAttr::ReprTransparent => {
19992011
is_transparent = true;
20002012
match target {
@@ -2057,13 +2069,20 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
20572069
target: target.to_string(),
20582070
});
20592071
}
2060-
if is_explicit_rust && (int_reprs > 0 || is_c || is_simd) {
2072+
if is_explicit_rust && (int_reprs > 0 || is_c || is_simd || is_scalable) {
20612073
let hint_spans = hint_spans.clone().collect();
20622074
self.dcx().emit_err(errors::ReprConflicting { hint_spans });
20632075
}
2064-
// Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
2076+
// Warn on `repr(scalable(N))` w/out `repr(simd)`
2077+
// i.e. only `repr(simd, scalable(N))` permitted
2078+
if is_scalable && !is_simd {
2079+
let hint_spans = hint_spans.clone().collect();
2080+
self.dcx().emit_err(errors::ReprScalableWithoutSimd { hint_spans });
2081+
}
2082+
// Warn on repr(u8, u16), repr(C, simd), repr(C, scalable), and c-like-enum-repr(C, u8)
20652083
if (int_reprs > 1)
20662084
|| (is_simd && is_c)
2085+
|| (is_scalable && is_c)
20672086
|| (int_reprs == 1
20682087
&& is_c
20692088
&& item.is_some_and(|item| {

compiler/rustc_passes/src/errors.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,13 @@ pub(crate) struct ReprConflicting {
611611
pub hint_spans: Vec<Span>,
612612
}
613613

614+
#[derive(Diagnostic)]
615+
#[diag(passes_repr_scalable_without_simd)]
616+
pub(crate) struct ReprScalableWithoutSimd {
617+
#[primary_span]
618+
pub hint_spans: Vec<Span>,
619+
}
620+
614621
#[derive(Diagnostic)]
615622
#[diag(passes_repr_align_greater_than_target_max, code = E0589)]
616623
#[note]

0 commit comments

Comments
 (0)