Skip to content

Commit b3494b4

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 ad635e5 commit b3494b4

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
}
@@ -82,6 +83,13 @@ pub enum IntType {
8283
UnsignedInt(ast::UintTy),
8384
}
8485

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

compiler/rustc_attr_parsing/messages.ftl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ attr_parsing_rustc_allowed_unstable_pairing =
114114
attr_parsing_rustc_promotable_pairing =
115115
`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute
116116
117+
attr_parsing_scalable_missing_n =
118+
invalid `scalable(num)` attribute: `scalable` needs an argument
119+
.suggestion = supply an argument here
120+
117121
attr_parsing_soft_no_args =
118122
`soft` should not have any arguments
119123

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

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

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,3 +635,11 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
635635
diag
636636
}
637637
}
638+
639+
#[derive(Diagnostic)]
640+
#[diag(attr_parsing_scalable_missing_n)]
641+
pub(crate) struct ScalableAttrMissingN {
642+
#[primary_span]
643+
#[suggestion(applicability = "has-placeholders", code = "scalable(...)")]
644+
pub span: Span,
645+
}

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1513,6 +1513,7 @@ impl<'tcx> TyCtxt<'tcx> {
15131513
let mut size = None;
15141514
let mut max_align: Option<Align> = None;
15151515
let mut min_pack: Option<Align> = None;
1516+
let mut elt: Option<u32> = None;
15161517

15171518
// Generate a deterministically-derived seed from the item's path hash
15181519
// to allow for cross-crate compilation to actually work
@@ -1542,6 +1543,10 @@ impl<'tcx> TyCtxt<'tcx> {
15421543
}
15431544
attr::ReprTransparent => ReprFlags::IS_TRANSPARENT,
15441545
attr::ReprSimd => ReprFlags::IS_SIMD,
1546+
attr::ReprScalable(e) => {
1547+
elt = Some(e.elt as u32);
1548+
ReprFlags::IS_SCALABLE
1549+
}
15451550
attr::ReprInt(i) => {
15461551
size = Some(match i {
15471552
attr::IntType::SignedInt(x) => match x {
@@ -1586,7 +1591,14 @@ impl<'tcx> TyCtxt<'tcx> {
15861591
flags.insert(ReprFlags::IS_LINEAR);
15871592
}
15881593

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

15921604
/// 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
@@ -605,6 +605,9 @@ passes_repr_align_should_be_align =
605605
passes_repr_conflicting =
606606
conflicting representation hints
607607
608+
passes_repr_scalable_without_simd =
609+
`scalable` representation hint without `simd` representation hint
610+
608611
passes_rustc_allow_const_fn_unstable =
609612
attribute should be applied to `const fn`
610613
.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
@@ -1987,6 +1987,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
19871987
let mut is_explicit_rust = false;
19881988
let mut is_c = false;
19891989
let mut is_simd = false;
1990+
let mut is_scalable = false;
19901991
let mut is_transparent = false;
19911992

19921993
for (repr, repr_span) in reprs {
@@ -2055,6 +2056,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
20552056
continue;
20562057
}
20572058
}
2059+
ReprAttr::ReprScalable(..) => {
2060+
is_scalable = true;
2061+
if target != Target::Struct {
2062+
self.dcx().emit_err(errors::AttrApplication::Struct {
2063+
hint_span: *repr_span,
2064+
span,
2065+
});
2066+
} else {
2067+
continue;
2068+
}
2069+
}
20582070
ReprAttr::ReprTransparent => {
20592071
is_transparent = true;
20602072
match target {
@@ -2116,13 +2128,20 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
21162128
target: target.to_string(),
21172129
});
21182130
}
2119-
if is_explicit_rust && (int_reprs > 0 || is_c || is_simd) {
2131+
if is_explicit_rust && (int_reprs > 0 || is_c || is_simd || is_scalable) {
21202132
let hint_spans = hint_spans.clone().collect();
21212133
self.dcx().emit_err(errors::ReprConflicting { hint_spans });
21222134
}
2123-
// Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
2135+
// Warn on `repr(scalable(N))` w/out `repr(simd)`
2136+
// i.e. only `repr(simd, scalable(N))` permitted
2137+
if is_scalable && !is_simd {
2138+
let hint_spans = hint_spans.clone().collect();
2139+
self.dcx().emit_err(errors::ReprScalableWithoutSimd { hint_spans });
2140+
}
2141+
// Warn on repr(u8, u16), repr(C, simd), repr(C, scalable), and c-like-enum-repr(C, u8)
21242142
if (int_reprs > 1)
21252143
|| (is_simd && is_c)
2144+
|| (is_scalable && is_c)
21262145
|| (int_reprs == 1
21272146
&& is_c
21282147
&& 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)