-
-
Notifications
You must be signed in to change notification settings - Fork 14.1k
rustc_scalable_vector(N)
#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
base: main
Are you sure you want to change the base?
rustc_scalable_vector(N)
#143924
Conversation
|
rustbot has assigned @compiler-errors. Use |
|
Some changes occurred in compiler/rustc_attr_parsing Some changes occurred in compiler/rustc_attr_data_structures Some changes occurred in compiler/rustc_passes/src/check_attr.rs Some changes occurred to the intrinsics. Make sure the CTFE / Miri interpreter cc @rust-lang/miri, @RalfJung, @oli-obk, @lcnr Some changes occurred to the CTFE / Miri interpreter cc @rust-lang/miri Some changes occurred to the platform-builtins intrinsics. Make sure the cc @antoyo, @GuillaumeGomez, @bjorn3, @calebzulawski, @programmerjake Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt Some changes occurred in compiler/rustc_codegen_ssa Some changes occurred in compiler/rustc_codegen_gcc changes to the core type system Some changes occurred to the CTFE machinery |
|
I've changed this back to a draft and marked it as |
cf9474d to
d58c634
Compare
This comment was marked as resolved.
This comment was marked as resolved.
0c22701 to
3ad0898
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
5c92874 to
3edf1b6
Compare
This comment has been minimized.
This comment has been minimized.
3edf1b6 to
4f6b823
Compare
workingjubilee
left a comment
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.
I do not intend to have repr(simd) survive this year, so I do not think this should be added.
Could you elaborate? |
|
I intend to replace it with an approach based on lang items for a variety of reasons, one of them being that to start with, the |
This comment was marked as outdated.
This comment was marked as outdated.
|
I don't think that making scalable vectors a non-const Sized type will work with SME since the size of scalable vectors can change depending on attributes placed on a function (ACLE spec). This is because there are 2 vector lengths (normal & streaming) and the length can changed based on CPU state. In C, the CPU state is controlled via function attributes, specifically:
Additionally, we will need to add compile-time checks to ensure scalable vectors aren't passed as arguments or returned across a mode change (ACLE spec). This essentially means that we can't support the use of scalable vectors in generic function signatures. I think the better approach is to go back to the original design in #118917 where scalable vectors are essentially extern types to which we add some capabilities. This avoids issues with generics since these types can never be passed as arguments or returned in a generic context. This design can still make use of the Sized type hierarchy since we still need the distinction between MetaSized and Unsized, with scalable vectors being the latter. |
tbh that sounds more like what we want is for Arm's scalable vectors to have a const-generic argument that's implicitly set by the surrounding function's mode which is either known (normal and locally-streaming functions), or a const-generic that's implicitly set by the caller (streaming-compatible functions). passing/returning scalable vectors between incompatible modes would then just produce a type error due to the const-generic argument not matching, but you can pass scalable vectors between compatible modes since the compiler can see the const-generic matches. |
|
@Amanieu My question is essentially as @programmerjake said: is there a reason that the SME and SVE modes are not two-or-more types, then? Whether the mode is a generic parameter or not is not too important to me, but it does seem intuitive to treat it as such. It's not like we can do FFI without knowing the mode, right? |
|
Documentation we'll want to reference while discussing this: |
|
@programmerjake I am sure Amanieu will provide more information, but one thing he pointed out when I asked in another context is that we would have to inhibit usage of SVE and SME types in the same function, because LLVM doesn't support switching modes except on function boundaries. However, it seems we will have to implement compile-time handling regarding functions for SVE and SME either way, so I suspect using the tools we already have for such would be better. We already have 3 types of functions which each require compile-time checking, after all. |
|
I don't think having 2 separate types for SVE and SME vectors is going to work. The main issue is that it's absolutely not possible to have scalable locals of 2 different modes in the same function. LLVM doesn't support it, and for good reason since even calculating the stack offsets for locals would involve several SME/SVE mode switches. The problem is that since these types would be runtime-sized, you would be able to smuggle those types into a function in various ways other than parameters and return values, and there's no way you can enforce this in a generic context. |
|
The main advantage of making SVE vectors fully unsized is that it allows us to reliably determine, before monomorphization, whether the signature of a function has SVE locals, parameters or return values. This means that:
The downsides are:
Overall I think the advantages outweigh the inconvenients and result in a simpler implementation in the compiler. It is also forward-compatible with making these types runtime-sized in the future. |
|
Hmmmm. Only requiring signature checking does help... I think I'm not overly attached to a specific direction but I'd like to have the FIXMEs reflect our current inclination, at least. |
|
I'm happy to land this as it is for now (with scalable vectors being |
Maybe I'm missing something, but how does making the vectors fully unsized let us determine that? You can still write generic functions that can be instantiated by fully unsized types: #![feature(extern_types)]
#![feature(sized_hierarchy)]
use std::marker::PointeeSized;
unsafe extern "C" {
type Bar;
fn get_bar() -> &'static Bar;
}
fn foo<T: PointeeSized>(x: &T) {}
fn main() {
foo::<Bar>(unsafe { get_bar() });
}In this example, The other disadvantage of making them fully unsized is that they can't be locals or return types or implement I've been thinking of the sizedness of these types as a distinct problem from what we do about streaming-vs-non-streaming and all of the issues related to these types needing the SVE target feature. If they are non-const Sized, then we can make these locals/return types/ |
|
Oh, I understand now what you meant by making the types fully unsized enabling us to determine whether there are locals, parameters or return types: because the generic parameter won't implement Nevertheless, I think my point is still the same, that we could make them non-const Sized and usable as locals and return types in SVE-enabled functions, and consider the limitations on generic instantiation a separate thing, giving us a bit more usability. |
6cdc8f7 to
d8b3d28
Compare
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
This comment has been minimized.
This comment has been minimized.
d8b3d28 to
6a9fb63
Compare
|
It's also unclear whether we will ever be able to enable the compiler to have more ambiguously-sized argument and return types in the future. I think we eventually will want to explicitly ban what we want to ban rather than relying on some other element of the language "doing it for us". If nothing else, for the sake of producing a better error message, at least. That doesn't have to be addressed here, obviously. |
compiler/rustc_abi/src/lib.rs
Outdated
| /// `N` in `rustc_scalable_vector(N)` - the element count of the scalable vector | ||
| ElementCount(u128), |
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.
This can just be u64. We will only parse 0..=u64::MAX and we will reject with an error things larger than 2.pow(16).
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.
I feel almost like we should say "factor" instead of "count" since the "actual count" is unknown until runtime but uses the N provided here as a factor, but then syntactically the count is whatever was given in the attribute, but then... anyway, either is good.
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.
I ended up changing it to u16 throughout as the attribute parsing pretty printer already had an impl for that and u128, not a particularly great reason, but 65535 is more than enough for this attribute.
compiler/rustc_abi/src/callconv.rs
Outdated
| })) | ||
| } | ||
|
|
||
| BackendRepr::ScalableVector { .. } => Err(Heterogeneous), |
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.
This seems like the wrong answer, they should be definitionally homogeneous, but maybe it's because we produce incorrect code if we answer as homogeneous?
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.
The original PR that this was based on did return Homogenous and added a new RegKind and so on, but I worked out that it was basically all dead code, even this line as it was when you reviewed.
classify_arg and classify_ret were bailing out earlier than the call to is_homogeneous_aggregate and it was keeping the PassMode::Direct that the function was called with, which I think is correct and works fine. I've added an explicit condition to bail out for scalable vectors in this case just so that happening is more obvious, and I've changed this to a unreachable! as it shouldn't be hit.
|
That last scan-through should be all, unless something is revealed (made apparent?) by the next iteration, so @rustbot author |
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 <[email protected]>
Extend well-formedness checking and HIR analysis to prohibit the use of scalable vectors in structs, enums, unions, tuples and arrays. LLVM does not support scalable vectors being members of other types, so these restrictions are necessary. Co-authored-by: Jamie Cunliffe <[email protected]>
Introduces `BackendRepr::ScalableVector` corresponding to scalable vector types annotated with `repr(scalable)` which lowers to a scalable vector type in LLVM. Co-authored-by: Jamie Cunliffe <[email protected]>
LLVM doesn't handle stores on `<vscale x N x i1>` for `N != 16`, a type used internally in SVE intrinsics. Spilling to the stack to create debuginfo will cause errors during instruction selection. These types that are an internal implementation detail to the intrinsic, so users should never see them types and won't need any debuginfo. Co-authored-by: Jamie Cunliffe <[email protected]>
Scalable vectors cannot be members of ADTs and thus cannot be kept over await points in async functions.
Scalable vector types only work with the relevant target features enabled, so require this for any function with the types in its signature.
The `fmt::Debug` impl for `TyAndLayout<'a, Ty>'` requires `fmt::Display` on the `Ty` parameter. In `ArgAbi`, `TyAndLayout`'s Ty` is instantiated with a parameter that implements `TyAbiInterface`. `TyAbiInterface` only required `fmt::Debug` be implemented on `Self`, not `fmt::Display`, which meant that it wasn't actually possible to debug print `ArgAbi`.
6a9fb63 to
fb3613f
Compare
Supercedes #118917.
Initial experimental implementation of rust-lang/rfcs#3838. Introduces a
rustc_scalable_vector(N)attribute that can be applied to types with a single[$ty]field (foru{16,32,64},i{16,32,64},f{32,64},bool).rustc_scalable_vectortypes are lowered to scalable vectors in the codegen backend.As with any unstable feature, there will necessarily be follow-ups as we experiment and find cases that we've not considered or still need some logic to handle, but this aims to be a decent baseline to start from.
See #145052 for request for a lang experiment.