Skip to content

Commit 911b435

Browse files
committed
builtin_macros/trait_sel: Copy/Clone derives
As scalable vectors are ultimately just registers, they should be able to implement `Copy` and `Clone`, which require some small special-casing in the compiler to ignore the field within the scalable vector types.
1 parent 4ee1999 commit 911b435

File tree

4 files changed

+134
-27
lines changed

4 files changed

+134
-27
lines changed

compiler/rustc_builtin_macros/src/deriving/clone.rs

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -33,37 +33,48 @@ pub(crate) fn expand_deriving_clone(
3333
let substructure;
3434
let is_simple;
3535
match item {
36-
Annotatable::Item(annitem) => match &annitem.kind {
37-
ItemKind::Struct(_, Generics { params, .. }, _)
38-
| ItemKind::Enum(_, Generics { params, .. }, _) => {
39-
let container_id = cx.current_expansion.id.expn_data().parent.expect_local();
40-
let has_derive_copy = cx.resolver.has_derive_copy(container_id);
41-
if has_derive_copy
42-
&& !params
43-
.iter()
44-
.any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
45-
{
46-
bounds = vec![];
36+
Annotatable::Item(annitem) => {
37+
let has_repr_scalable = annitem.attrs.iter().any(|attr| {
38+
attr.has_name(sym::repr)
39+
&& attr
40+
.meta_item_list()
41+
.map(|list| list.iter().any(|inner| inner.has_name(sym::scalable)))
42+
.unwrap_or(false)
43+
});
44+
45+
match &annitem.kind {
46+
ItemKind::Struct(_, Generics { params, .. }, _)
47+
| ItemKind::Enum(_, Generics { params, .. }, _) => {
48+
let container_id = cx.current_expansion.id.expn_data().parent.expect_local();
49+
let has_derive_copy = cx.resolver.has_derive_copy(container_id);
50+
if has_derive_copy
51+
&& !params
52+
.iter()
53+
.any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
54+
{
55+
bounds = vec![];
56+
is_simple = true;
57+
substructure = combine_substructure(Box::new(move |c, s, sub| {
58+
cs_clone_simple("Clone", c, s, sub, false, has_repr_scalable)
59+
}));
60+
} else {
61+
bounds = vec![];
62+
is_simple = false;
63+
substructure = combine_substructure(Box::new(|c, s, sub| {
64+
cs_clone("Clone", c, s, sub)
65+
}));
66+
}
67+
}
68+
ItemKind::Union(..) => {
69+
bounds = vec![Path(path_std!(marker::Copy))];
4770
is_simple = true;
48-
substructure = combine_substructure(Box::new(|c, s, sub| {
49-
cs_clone_simple("Clone", c, s, sub, false)
71+
substructure = combine_substructure(Box::new(move |c, s, sub| {
72+
cs_clone_simple("Clone", c, s, sub, true, has_repr_scalable)
5073
}));
51-
} else {
52-
bounds = vec![];
53-
is_simple = false;
54-
substructure =
55-
combine_substructure(Box::new(|c, s, sub| cs_clone("Clone", c, s, sub)));
5674
}
75+
_ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on wrong item kind"),
5776
}
58-
ItemKind::Union(..) => {
59-
bounds = vec![Path(path_std!(marker::Copy))];
60-
is_simple = true;
61-
substructure = combine_substructure(Box::new(|c, s, sub| {
62-
cs_clone_simple("Clone", c, s, sub, true)
63-
}));
64-
}
65-
_ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on wrong item kind"),
66-
},
77+
}
6778

6879
_ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on trait item or impl item"),
6980
}
@@ -98,6 +109,7 @@ fn cs_clone_simple(
98109
trait_span: Span,
99110
substr: &Substructure<'_>,
100111
is_union: bool,
112+
has_repr_scalable: bool,
101113
) -> BlockOrExpr {
102114
let mut stmts = ThinVec::new();
103115
let mut seen_type_names = FxHashSet::default();
@@ -112,6 +124,9 @@ fn cs_clone_simple(
112124
// Already produced an assertion for this type.
113125
// Anonymous structs or unions must be eliminated as they cannot be
114126
// type parameters.
127+
} else if has_repr_scalable {
128+
// Fields of scalable vector types are just markers for codegen, don't assert they
129+
// implement `Clone`
115130
} else {
116131
// let _: AssertParamIsClone<FieldTy>;
117132
super::assert_ty_bounds(

compiler/rustc_trait_selection/src/traits/misc.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ pub fn type_allowed_to_implement_copy<'tcx>(
6666
_ => return Err(CopyImplementationError::NotAnAdt),
6767
};
6868

69+
// Scalable vectors have an unsized field that would normally disallow a `Copy` impl on the
70+
// type, but that type doesn't actually exist, it's just a marker to know the element type of
71+
// the vector. After codegen, scalable vectors are just a register that can be trivially copied.
72+
if adt.repr().scalable() {
73+
return Ok(());
74+
}
75+
6976
all_fields_implement_trait(
7077
tcx,
7178
param_env,

tests/codegen/simd/scalable.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//@ compile-flags: -C opt-level=2
2+
//@ edition: 2021
3+
//@ only-aarch64
4+
5+
#![crate_type = "lib"]
6+
#![allow(incomplete_features, internal_features)]
7+
#![feature(repr_simd, repr_scalable, simd_ffi, link_llvm_intrinsics)]
8+
9+
#[derive(Copy, Clone)]
10+
#[repr(simd, scalable(4))]
11+
#[allow(non_camel_case_types)]
12+
pub struct svint32_t {
13+
_ty: [i32],
14+
}
15+
16+
#[inline(never)]
17+
#[target_feature(enable = "sve")]
18+
pub unsafe fn svdup_n_s32(op: i32) -> svint32_t {
19+
extern "C" {
20+
#[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.dup.x.nxv4i32")]
21+
fn _svdup_n_s32(op: i32) -> svint32_t;
22+
}
23+
unsafe { _svdup_n_s32(op) }
24+
}
25+
26+
#[inline]
27+
#[target_feature(enable = "sve,sve2")]
28+
pub unsafe fn svxar_n_s32<const IMM3: i32>(op1: svint32_t, op2: svint32_t) -> svint32_t {
29+
extern "C" {
30+
#[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.xar.nxv4i32")]
31+
fn _svxar_n_s32(op1: svint32_t, op2: svint32_t, imm3: i32) -> svint32_t;
32+
}
33+
unsafe { _svxar_n_s32(op1, op2, IMM3) }
34+
}
35+
36+
#[inline(never)]
37+
#[no_mangle]
38+
#[target_feature(enable = "sve,sve2")]
39+
// CHECK: define <vscale x 4 x i32> @pass_as_ref(ptr noalias nocapture noundef readonly align 4 dereferenceable(4) %a, <vscale x 4 x i32> %b)
40+
pub unsafe fn pass_as_ref(a: &svint32_t, b: svint32_t) -> svint32_t {
41+
// CHECK: load <vscale x 4 x i32>, ptr %a, align 4
42+
svxar_n_s32::<1>(*a, b)
43+
}
44+
45+
#[no_mangle]
46+
#[target_feature(enable = "sve,sve2")]
47+
// CHECK: define <vscale x 4 x i32> @test()
48+
pub unsafe fn test() -> svint32_t {
49+
let a = svdup_n_s32(1);
50+
let b = svdup_n_s32(2);
51+
// CHECK: call <vscale x 4 x i32> @pass_as_ref(ptr noalias noundef nonnull readonly align 4 dereferenceable(4) %a, <vscale x 4 x i32> %b)
52+
pass_as_ref(&a, b)
53+
}

tests/ui/simd/scalable/copy-clone.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//@ build-pass
2+
//@ only-aarch64
3+
#![feature(link_llvm_intrinsics, repr_simd, repr_scalable, simd_ffi)]
4+
5+
#[derive(Copy, Clone)]
6+
#[repr(simd, scalable(4))]
7+
#[allow(non_camel_case_types)]
8+
pub struct svint32_t {
9+
_ty: [i32],
10+
}
11+
12+
#[target_feature(enable = "sve")]
13+
pub unsafe fn svdup_n_s32(op: i32) -> svint32_t {
14+
extern "C" {
15+
#[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.dup.x.nxv4i32")]
16+
fn _svdup_n_s32(op: i32) -> svint32_t;
17+
}
18+
unsafe { _svdup_n_s32(op) }
19+
}
20+
21+
#[target_feature(enable = "sve")]
22+
fn require_copy<T: Copy>(t: T) {}
23+
24+
#[target_feature(enable = "sve")]
25+
fn test() {
26+
unsafe {
27+
let a = svdup_n_s32(1);
28+
require_copy(a);
29+
}
30+
}
31+
32+
fn main() {}

0 commit comments

Comments
 (0)