Skip to content

repr(scalable) #143924

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler/rustc_abi/src/callconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
}))
}

BackendRepr::ScalableVector { .. } => Err(Heterogeneous),

BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => {
// Helper for computing `homogeneous_aggregate`, allowing a custom
// starting offset (used below for handling variants).
Expand Down
12 changes: 10 additions & 2 deletions compiler/rustc_abi/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
element: F,
count: u64,
repr_packed: bool,
scalable: Option<u32>,
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
let elt = element.as_ref();
if count == 0 {
Expand All @@ -169,7 +170,12 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
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() {
let (repr, align) = if let Some(elt) = scalable {
(
BackendRepr::ScalableVector { element: e_repr, count: elt as u64 },
dl.llvmlike_vector_align(size),
)
} else 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.
Expand Down Expand Up @@ -461,6 +467,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
BackendRepr::Scalar(..)
| BackendRepr::ScalarPair(..)
| BackendRepr::SimdVector { .. }
| BackendRepr::ScalableVector { .. }
| BackendRepr::Memory { .. } => repr,
},
};
Expand Down Expand Up @@ -532,7 +539,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;
Expand Down
44 changes: 41 additions & 3 deletions compiler/rustc_abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,11 @@ bitflags! {
// Other flags can still inhibit reordering and thus randomization.
// The seed stored in `ReprOptions.field_shuffle_seed`.
const RANDOMIZE_LAYOUT = 1 << 4;
const IS_SCALABLE = 1 << 5;
// 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();
}
Expand Down Expand Up @@ -143,6 +145,7 @@ pub struct ReprOptions {
pub align: Option<Align>,
pub pack: Option<Align>,
pub flags: ReprFlags,
pub scalable: Option<u32>,
/// The seed to be used for randomizing a type's layout
///
/// Note: This could technically be a `u128` which would
Expand All @@ -159,6 +162,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)
Expand Down Expand Up @@ -1663,6 +1671,10 @@ impl AddressSpace {
pub enum BackendRepr {
Scalar(Scalar),
ScalarPair(Scalar, Scalar),
ScalableVector {
element: Scalar,
count: u64,
},
SimdVector {
element: Scalar,
count: u64,
Expand All @@ -1681,6 +1693,9 @@ impl BackendRepr {
match *self {
BackendRepr::Scalar(_)
| BackendRepr::ScalarPair(..)
// FIXME(repr_scalable): Scalable vectors are forced to be `Sized` while the
// `sized_hierarchy` feature is not yet fully implemented
| BackendRepr::ScalableVector { .. }
| BackendRepr::SimdVector { .. } => false,
BackendRepr::Memory { sized } => !sized,
}
Expand Down Expand Up @@ -1721,7 +1736,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,
}
}

Expand All @@ -1743,7 +1760,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,
}
}

Expand All @@ -1758,6 +1777,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 }
}
}
}

Expand Down Expand Up @@ -1998,7 +2020,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,
}
}
Expand Down Expand Up @@ -2092,6 +2116,19 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
self.is_sized() && self.size.bytes() == 0 && self.align.abi.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
Expand All @@ -2100,6 +2137,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,
}
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,15 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
"SIMD types are experimental and possibly buggy"
);
}

if item.has_name(sym::scalable) {
gate!(
&self,
repr_scalable,
attr.span,
"scalable vector types are experimental"
);
}
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_attr_data_structures/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ pub enum ReprAttr {
ReprC,
ReprPacked(Align),
ReprSimd,
ReprScalable(ScalableElt),
ReprTransparent,
ReprAlign(Align),
}
Expand All @@ -82,6 +83,13 @@ pub enum IntType {
UnsignedInt(ast::UintTy),
}

/// The base multiple of lanes that are in a scalable vector.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Encodable, Decodable, HashStable_Generic, PrintAttribute)]
pub struct ScalableElt {
pub elt: u16,
}

#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)]
pub struct Deprecation {
pub since: DeprecatedSince,
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_attr_parsing/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ 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_scalable_missing_n =
invalid `scalable(num)` attribute: `scalable` needs an argument
.suggestion = supply an argument here

attr_parsing_soft_no_args =
`soft` should not have any arguments

Expand Down
22 changes: 21 additions & 1 deletion compiler/rustc_attr_parsing/src/attributes/repr.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use rustc_abi::Align;
use rustc_ast::{IntTy, LitIntType, LitKind, UintTy};
use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr};
use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr, ScalableElt};
use rustc_feature::{AttributeTemplate, template};
use rustc_span::{DUMMY_SP, Span, Symbol, sym};

Expand Down Expand Up @@ -144,6 +144,11 @@ fn parse_repr<S: Stage>(
(Some(sym::Rust), ArgParser::NoArgs) => Some(ReprRust),
(Some(sym::C), ArgParser::NoArgs) => Some(ReprC),
(Some(sym::simd), ArgParser::NoArgs) => Some(ReprSimd),
(Some(sym::scalable), ArgParser::List(l)) => parse_repr_scalable(cx, l, param.span()),
(Some(sym::scalable), ArgParser::NoArgs) => {
cx.emit_err(session_diagnostics::ScalableAttrMissingN { span: param.span() });
None
}
(Some(sym::transparent), ArgParser::NoArgs) => Some(ReprTransparent),
(Some(name @ int_pat!()), ArgParser::NoArgs) => {
// int_pat!() should make sure it always parses
Expand Down Expand Up @@ -322,3 +327,18 @@ impl<S: Stage> AttributeParser<S> for AlignParser {
Some(AttributeKind::Align { align, span })
}
}

fn parse_repr_scalable<S: Stage>(
cx: &AcceptContext<'_, '_, S>,
list: &MetaItemListParser<'_>,
span: Span,
) -> Option<ReprAttr> {
let Some(LitKind::Int(literal, LitIntType::Unsuffixed)) =
list.single().and_then(|elt| elt.lit()).map(|lit| lit.kind)
else {
cx.emit_err(session_diagnostics::ScalableAttrMissingN { span });
return None;
};

literal.get().try_into().ok().map(|elt| ReprAttr::ReprScalable(ScalableElt { elt }))
}
8 changes: 8 additions & 0 deletions compiler/rustc_attr_parsing/src/session_diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -635,3 +635,11 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
diag
}
}

#[derive(Diagnostic)]
#[diag(attr_parsing_scalable_missing_n)]
pub(crate) struct ScalableAttrMissingN {
#[primary_span]
#[suggestion(applicability = "has-placeholders", code = "scalable(...)")]
pub span: Span,
}
69 changes: 42 additions & 27 deletions compiler/rustc_builtin_macros/src/deriving/clone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,37 +33,48 @@ pub(crate) fn expand_deriving_clone(
let substructure;
let is_simple;
match item {
Annotatable::Item(annitem) => match &annitem.kind {
ItemKind::Struct(_, Generics { params, .. }, _)
| ItemKind::Enum(_, Generics { params, .. }, _) => {
let container_id = cx.current_expansion.id.expn_data().parent.expect_local();
let has_derive_copy = cx.resolver.has_derive_copy(container_id);
if has_derive_copy
&& !params
.iter()
.any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
{
bounds = vec![];
Annotatable::Item(annitem) => {
let has_repr_scalable = annitem.attrs.iter().any(|attr| {
attr.has_name(sym::repr)
&& attr
.meta_item_list()
.map(|list| list.iter().any(|inner| inner.has_name(sym::scalable)))
.unwrap_or(false)
});

match &annitem.kind {
ItemKind::Struct(_, Generics { params, .. }, _)
| ItemKind::Enum(_, Generics { params, .. }, _) => {
let container_id = cx.current_expansion.id.expn_data().parent.expect_local();
let has_derive_copy = cx.resolver.has_derive_copy(container_id);
if has_derive_copy
&& !params
.iter()
.any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
{
bounds = vec![];
is_simple = true;
substructure = combine_substructure(Box::new(move |c, s, sub| {
cs_clone_simple("Clone", c, s, sub, false, has_repr_scalable)
}));
} else {
bounds = vec![];
is_simple = false;
substructure = combine_substructure(Box::new(|c, s, sub| {
cs_clone("Clone", c, s, sub)
}));
}
}
ItemKind::Union(..) => {
bounds = vec![Path(path_std!(marker::Copy))];
is_simple = true;
substructure = combine_substructure(Box::new(|c, s, sub| {
cs_clone_simple("Clone", c, s, sub, false)
substructure = combine_substructure(Box::new(move |c, s, sub| {
cs_clone_simple("Clone", c, s, sub, true, has_repr_scalable)
}));
} else {
bounds = vec![];
is_simple = false;
substructure =
combine_substructure(Box::new(|c, s, sub| cs_clone("Clone", c, s, sub)));
}
_ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on wrong item kind"),
}
ItemKind::Union(..) => {
bounds = vec![Path(path_std!(marker::Copy))];
is_simple = true;
substructure = combine_substructure(Box::new(|c, s, sub| {
cs_clone_simple("Clone", c, s, sub, true)
}));
}
_ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on wrong item kind"),
},
}

_ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on trait item or impl item"),
}
Expand Down Expand Up @@ -98,6 +109,7 @@ fn cs_clone_simple(
trait_span: Span,
substr: &Substructure<'_>,
is_union: bool,
has_repr_scalable: bool,
) -> BlockOrExpr {
let mut stmts = ThinVec::new();
let mut seen_type_names = FxHashSet::default();
Expand All @@ -112,6 +124,9 @@ fn cs_clone_simple(
// Already produced an assertion for this type.
// Anonymous structs or unions must be eliminated as they cannot be
// type parameters.
} else if has_repr_scalable {
// Fields of scalable vector types are just markers for codegen, don't assert they
// implement `Clone`
} else {
// let _: AssertParamIsClone<FieldTy>;
super::assert_ty_bounds(
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_codegen_gcc/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -926,6 +926,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();
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,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`),
Expand Down
Loading
Loading