Skip to content

Commit ae1aac0

Browse files
committed
Allow SVE types to be taken by reference.
Ensures that an SVE type can have a reference taken to it. This currently emits a `dereferenceable` attribute for the ptr using the element size as the number of bytes. While not perfect this is correct as a vector will always have a least one primitive.
1 parent 6321f69 commit ae1aac0

File tree

8 files changed

+73
-12
lines changed

8 files changed

+73
-12
lines changed

compiler/rustc_codegen_llvm/src/builder.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -538,10 +538,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
538538
panic!("unsized locals must not be `extern` types");
539539
}
540540
}
541-
assert_eq!(
542-
place.llextra.is_some(),
543-
place.layout.is_unsized() && !place.layout.is_runtime_sized()
544-
);
541+
542+
if !place.layout.is_runtime_sized() {
543+
assert_eq!(place.llextra.is_some(), place.layout.is_unsized());
544+
}
545545

546546
if place.layout.is_zst() {
547547
return OperandRef::zero_sized(place.layout);

compiler/rustc_codegen_ssa/src/mir/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
235235

236236
if memory_locals.contains(local) {
237237
debug!("alloc: {:?} -> place", local);
238-
if layout.is_unsized() {
238+
if layout.is_unsized() && !layout.is_runtime_sized() {
239239
LocalRef::UnsizedPlace(PlaceRef::alloca_unsized_indirect(&mut start_bx, layout))
240240
} else {
241241
LocalRef::Place(PlaceRef::alloca(&mut start_bx, layout))

compiler/rustc_codegen_ssa/src/traits/type_.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {
7878

7979
fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool {
8080
let param_env = ty::ParamEnv::reveal_all();
81-
if ty.is_sized(self.tcx(), param_env) {
81+
if ty.is_sized(self.tcx(), param_env) || ty.is_scalable_simd() {
8282
return false;
8383
}
8484

compiler/rustc_mir_build/src/build/expr/as_operand.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
165165
let ty = expr.ty;
166166
let param_env = this.param_env;
167167

168-
if !ty.is_sized(tcx, param_env) {
169-
// !sized means !copy, so this is an unsized move unless it's a scalable SIMD type.
170-
if !ty.is_scalable_simd() {
171-
assert!(!ty.is_copy_modulo_regions(tcx, param_env));
172-
}
168+
if !ty.is_sized(tcx, param_env) && !ty.is_scalable_simd() {
169+
// !sized means !copy, so this is an unsized move.
170+
assert!(!ty.is_copy_modulo_regions(tcx, param_env));
173171

174172
// As described above, detect the case where we are passing a value of unsized
175173
// type, and that value is coming from the deref of a box.

compiler/rustc_monomorphize/src/collector.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1194,7 +1194,7 @@ fn find_vtable_types_for_unsizing<'tcx>(
11941194
let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| {
11951195
let param_env = ty::ParamEnv::reveal_all();
11961196
let type_has_metadata = |ty: Ty<'tcx>| -> bool {
1197-
if ty.is_sized(tcx.tcx, param_env) {
1197+
if ty.is_sized(tcx.tcx, param_env) || ty.is_scalable_simd() {
11981198
return false;
11991199
}
12001200
let tail = tcx.struct_tail_erasing_lifetimes(ty, param_env);

compiler/rustc_ty_utils/src/layout.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,9 @@ fn layout_of_uncached<'tcx>(
164164
}
165165

166166
let pointee = tcx.normalize_erasing_regions(param_env, pointee);
167+
if pointee.is_scalable_simd() {
168+
return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
169+
}
167170
if pointee.is_sized(tcx, param_env) {
168171
return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
169172
}

library/core/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
// rustc itself never sets the feature, so this line has no effect there.
6363
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
6464
#![stable(feature = "core", since = "1.6.0")]
65+
#![cfg_attr(not(bootstrap), feature(repr_scalable))]
6566
#![doc(
6667
html_playground_url = "https://play.rust-lang.org/",
6768
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//@ only-aarch64
2+
//@ compile-flags: -C opt-level=2 --edition=2021
3+
4+
#![crate_type = "lib"]
5+
6+
#![allow(incomplete_features, internal_features, improper_ctypes)]
7+
#![feature(
8+
repr_simd,
9+
repr_scalable,
10+
simd_ffi,
11+
unsized_locals,
12+
unsized_fn_params,
13+
link_llvm_intrinsics
14+
)]
15+
16+
#[repr(simd, scalable(4))]
17+
#[allow(non_camel_case_types)]
18+
pub struct svint32_t {
19+
_ty: [i32],
20+
}
21+
22+
#[inline(never)]
23+
#[target_feature(enable = "sve")]
24+
pub unsafe fn svdup_n_s32(op: i32) -> svint32_t {
25+
extern "C" {
26+
#[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.dup.x.nxv4i32")]
27+
fn _svdup_n_s32(op: i32) -> svint32_t;
28+
}
29+
unsafe { _svdup_n_s32(op) }
30+
}
31+
32+
#[inline]
33+
#[target_feature(enable = "sve,sve2")]
34+
pub unsafe fn svxar_n_s32<const IMM3: i32>(op1: svint32_t, op2: svint32_t) -> svint32_t {
35+
extern "C" {
36+
#[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.xar.nxv4i32")]
37+
fn _svxar_n_s32(op1: svint32_t, op2: svint32_t, imm3: i32) -> svint32_t;
38+
}
39+
unsafe { _svxar_n_s32(op1, op2, IMM3) }
40+
}
41+
42+
#[inline(never)]
43+
#[no_mangle]
44+
#[target_feature(enable = "sve,sve2")]
45+
// 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)
46+
pub unsafe fn pass_as_ref(a: &svint32_t, b: svint32_t) -> svint32_t {
47+
// CHECK: load <vscale x 4 x i32>, ptr %a, align 4
48+
svxar_n_s32::<1>(*a, b)
49+
}
50+
51+
#[no_mangle]
52+
#[target_feature(enable = "sve,sve2")]
53+
// CHECK: define <vscale x 4 x i32> @test()
54+
pub unsafe fn test() -> svint32_t {
55+
let a = svdup_n_s32(1);
56+
let b = svdup_n_s32(2);
57+
// 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)
58+
pass_as_ref(&a, b)
59+
}

0 commit comments

Comments
 (0)