-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Support for a scalable simd representation #118917
base: master
Are you sure you want to change the base?
Changes from all commits
aee9788
6624e8a
5869f9d
0324ff4
0a956db
c4f8a92
dace184
d5834cc
e237c35
e23a944
1adf6ca
f18804e
63f9d37
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,9 +47,11 @@ bitflags! { | |
// If true, the type's layout can be randomized using | ||
// 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 IS_UNOPTIMISABLE = ReprFlags::IS_C.bits() | ||
| ReprFlags::IS_SIMD.bits() | ||
| ReprFlags::IS_SCALABLE.bits() | ||
| ReprFlags::IS_LINEAR.bits(); | ||
} | ||
} | ||
|
@@ -90,6 +92,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 | ||
|
@@ -106,6 +109,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) | ||
|
@@ -1306,6 +1314,10 @@ pub enum Abi { | |
Uninhabited, | ||
Scalar(Scalar), | ||
ScalarPair(Scalar, Scalar), | ||
ScalableVector { | ||
element: Scalar, | ||
elt: u64, | ||
}, | ||
Vector { | ||
element: Scalar, | ||
count: u64, | ||
|
@@ -1323,6 +1335,7 @@ impl Abi { | |
match *self { | ||
Abi::Uninhabited | Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false, | ||
Abi::Aggregate { sized } => !sized, | ||
Abi::ScalableVector { .. } => true, | ||
} | ||
} | ||
|
||
|
@@ -1369,7 +1382,7 @@ impl Abi { | |
Abi::Vector { element, count } => { | ||
cx.data_layout().vector_align(element.size(cx) * count) | ||
} | ||
Abi::Uninhabited | Abi::Aggregate { .. } => return None, | ||
Abi::Uninhabited | Abi::Aggregate { .. } | Abi::ScalableVector { .. } => return None, | ||
}) | ||
} | ||
|
||
|
@@ -1390,7 +1403,7 @@ impl Abi { | |
// to make the size a multiple of align (e.g. for vectors of size 3). | ||
(element.size(cx) * count).align_to(self.inherent_align(cx)?.abi) | ||
} | ||
Abi::Uninhabited | Abi::Aggregate { .. } => return None, | ||
Abi::Uninhabited | Abi::Aggregate { .. } | Abi::ScalableVector { .. } => return None, | ||
}) | ||
} | ||
|
||
|
@@ -1400,6 +1413,9 @@ impl Abi { | |
Abi::Scalar(s) => Abi::Scalar(s.to_union()), | ||
Abi::ScalarPair(s1, s2) => Abi::ScalarPair(s1.to_union(), s2.to_union()), | ||
Abi::Vector { element, count } => Abi::Vector { element: element.to_union(), count }, | ||
Abi::ScalableVector { element, elt } => { | ||
Abi::ScalableVector { element: element.to_union(), elt } | ||
} | ||
Abi::Uninhabited | Abi::Aggregate { .. } => Abi::Aggregate { sized: true }, | ||
} | ||
} | ||
|
@@ -1686,6 +1702,11 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutS<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.abi, Abi::ScalableVector { .. }) | ||
Comment on lines
+1705
to
+1707
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This coexisting with Also, the possibility of knowing the size at all feels like an edge case out of all possible "value-only"/"memory-unrepresentable" types discussed in e.g. these older RFC comments:
As far as |
||
} | ||
|
||
/// 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 | ||
|
@@ -1695,6 +1716,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutS<FieldIdx, VariantIdx> { | |
Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false, | ||
Abi::Uninhabited => self.size.bytes() == 0, | ||
Abi::Aggregate { sized } => sized && self.size.bytes() == 0, | ||
Abi::ScalableVector { .. } => false, | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -267,6 +267,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 SIMD types are experimental and possibly buggy" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we call these I'm not suggesting or requesting a change here, just making an observation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using the term scalable vector types can also cause confusion. I have spoken with a few people that when you say scalable vectors, they think it's something to with vectors in the sense of a Saying they allow the vector length to change at runtime is not correct here, that would be considered undefined behavior with SVE in LLVM and Rust. With SVE the vector length isn't changed, rather lanes are masked off. Changing vector length at runtime for SVE could lead to an incorrect stack if any SVE register was spilled to the stack. During execution SVE should be a fixed vector size with lanes ignored (for predicated instructions) based on the governing predicate. |
||
); | ||
} | ||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -522,7 +522,15 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { | |
place_ty = self.sanitize_projection(place_ty, elem, place, location, context); | ||
} | ||
|
||
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { | ||
// The Copy trait isn't implemented for scalable SIMD types. | ||
// These types live somewhere between `Sized` and `Unsize`. | ||
// The bounds on `Copy` disallow the trait from being | ||
// implemented for them. As a result of this no bounds from | ||
// `Copy` apply for the type, therefore, skipping this check | ||
// should be perfectly legal. | ||
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context | ||
&& !place_ty.ty.is_scalable_simd() | ||
{ | ||
let tcx = self.tcx(); | ||
let trait_ref = ty::TraitRef::new( | ||
tcx, | ||
|
@@ -1267,7 +1275,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | |
} | ||
|
||
self.check_rvalue(body, rv, location); | ||
if !self.unsized_feature_enabled() { | ||
if !(self.unsized_feature_enabled() || place_ty.is_scalable_simd()) { | ||
let trait_ref = ty::TraitRef::new( | ||
tcx, | ||
tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), | ||
|
@@ -1788,7 +1796,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | |
if !self.unsized_feature_enabled() { | ||
let span = local_decl.source_info.span; | ||
let ty = local_decl.ty; | ||
self.ensure_place_sized(ty, span); | ||
if !ty.is_scalable_simd() { | ||
self.ensure_place_sized(ty, span); | ||
} | ||
} | ||
} | ||
|
||
|
@@ -1804,11 +1814,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | |
// expressions evaluate through `as_temp` or `into` a return | ||
// slot or local, so to find all unsized rvalues it is enough | ||
// to check all temps, return slots and locals. | ||
if self.reported_errors.replace((ty, span)).is_none() { | ||
// While this is located in `nll::typeck` this error is not | ||
// an NLL error, it's a required check to prevent creation | ||
// of unsized rvalues in a call expression. | ||
self.tcx().dcx().emit_err(MoveUnsized { ty, span }); | ||
if !ty.is_scalable_simd() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not needed, it's already handled in the callers of |
||
if self.reported_errors.replace((ty, span)).is_none() { | ||
// While this is located in `nll::typeck` this error is not | ||
// an NLL error, it's a required check to prevent creation | ||
// of unsized rvalues in a call expression. | ||
self.tcx().dcx().emit_err(MoveUnsized { ty, span }); | ||
} | ||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -126,6 +126,11 @@ impl LlvmType for Reg { | |
_ => bug!("unsupported float: {:?}", self), | ||
}, | ||
RegKind::Vector => cx.type_vector(cx.type_i8(), self.size.bytes()), | ||
// Generate a LLVM type such as <vscale x 16 x i8>, like above for a non scalable | ||
// vector. The use of 16 here is chosen as that will generate a valid type with both | ||
// Arm SVE and RISC-V RVV. In the future with other architectures this might not be | ||
// valid and might have to be configured by the target. | ||
RegKind::ScalableVector => cx.type_scalable_vector(cx.type_i8(), 16), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could use a comment. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we use i8 and 16 instead of basing it off of the original type information? |
||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -537,7 +537,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { | |||||||||
panic!("unsized locals must not be `extern` types"); | ||||||||||
} | ||||||||||
} | ||||||||||
assert_eq!(place.val.llextra.is_some(), place.layout.is_unsized()); | ||||||||||
|
||||||||||
if !place.layout.is_runtime_sized() { | ||||||||||
assert_eq!(place.val.llextra.is_some(), place.layout.is_unsized()); | ||||||||||
} | ||||||||||
Comment on lines
+541
to
+543
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
|
||||||||||
if place.layout.is_zst() { | ||||||||||
return OperandRef::zero_sized(place.layout); | ||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1091,6 +1091,7 @@ fn build_struct_type_di_node<'ll, 'tcx>( | |
Cow::Borrowed(f.name.as_str()) | ||
}; | ||
let field_layout = struct_type_and_layout.field(cx, i); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: unrelated newline? |
||
build_field_di_node( | ||
cx, | ||
owner, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
elt
->elt_cnt
?