Skip to content

Commit 8ab9370

Browse files
committed
cg_llvm: sve_undef intrinsic
Intrinsic definitions previously used `transmute_unchecked(())` to generate a poison value for `svundef*` intrinsics, but it's better to be explicit and have a builtin intrinsic for this than do it via a cast.
1 parent 2e7a501 commit 8ab9370

6 files changed

Lines changed: 99 additions & 0 deletions

File tree

compiler/rustc_codegen_llvm/src/intrinsic.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::cmp::Ordering;
22
use std::ffi::c_uint;
3+
use std::ops::Deref as _;
34
use std::ptr;
45

56
use rustc_abi::{
@@ -674,6 +675,12 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
674675
)
675676
}
676677

678+
sym::sve_undef => {
679+
let vec_ty = self.layout_of(fn_args.type_at(0));
680+
assert!(vec_ty.deref().is_scalable_vector());
681+
self.const_poison(self.backend_type(vec_ty))
682+
}
683+
677684
_ if name.as_str().starts_with("simd_") => {
678685
// Unpack non-power-of-2 #[repr(packed, simd)] arguments.
679686
// This gives them the expected layout of a regular #[repr(simd)] vector.

compiler/rustc_codegen_ssa/src/mir/intrinsic.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
116116
| sym::assert_zero_valid
117117
| sym::assert_mem_uninitialized_valid
118118
| sym::assert_inhabited
119+
| sym::sve_undef
119120
| sym::ub_checks
120121
| sym::contract_checks
121122
| sym::atomic_fence

compiler/rustc_hir_analysis/src/check/intrinsic.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,7 @@ pub(crate) fn check_intrinsic_type(
783783
sym::sve_tuple_create4 => (2, 0, vec![param(0), param(0), param(0), param(0)], param(1)),
784784
sym::sve_tuple_get => (2, 1, vec![param(0)], param(1)),
785785
sym::sve_tuple_set => (2, 1, vec![param(0), param(1)], param(0)),
786+
sym::sve_undef => (1, 0, vec![], param(0)),
786787

787788
sym::atomic_cxchg | sym::atomic_cxchgweak => (
788789
1,

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1974,6 +1974,7 @@ symbols! {
19741974
sve_tuple_create4,
19751975
sve_tuple_get,
19761976
sve_tuple_set,
1977+
sve_undef,
19771978
sym,
19781979
sync,
19791980
synthetic,

library/core/src/intrinsics/scalable.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22
//!
33
//! In this module, a "vector" is any `#[rustc_scalable_vector]`-annotated type.
44
5+
/// Return an uninitialised vector.
6+
///
7+
/// `SVec` must be a scalable vector or scalable vector tuple.
8+
#[cfg(target_arch = "aarch64")]
9+
#[rustc_intrinsic]
10+
#[rustc_nounwind]
11+
#[target_feature(enable = "sve")]
12+
pub unsafe fn sve_undef<SVec>() -> SVec;
13+
514
/// Create a tuple of two vectors.
615
///
716
/// `SVecTup` must be a scalable vector tuple (`#[rustc_scalable_vector]`) and `SVec` must be a
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//@ compile-flags: -Copt-level=0
2+
//@ only-aarch64
3+
#![allow(incomplete_features, internal_features, improper_ctypes, private_interfaces, unused)]
4+
#![crate_type = "bin"]
5+
#![feature(
6+
core_intrinsics,
7+
simd_ffi,
8+
rustc_attrs,
9+
target_feature_inline_always,
10+
abi_unadjusted,
11+
link_llvm_intrinsics
12+
)]
13+
14+
use std::arch::aarch64::int8x16_t;
15+
use std::mem::transmute;
16+
17+
// Test that the use of the `sve_undef` intrinsic produces the expected LLVM IR that will not
18+
// segfault at runtime.
19+
20+
#[rustc_scalable_vector(16)]
21+
#[allow(non_camel_case_types)]
22+
struct svint8_t(i8);
23+
24+
#[inline(always)]
25+
#[target_feature(enable = "sve")]
26+
pub unsafe fn svundef_s8() -> svint8_t {
27+
std::intrinsics::scalable::sve_undef()
28+
}
29+
30+
// CHECK: ; sve_undef::test_ffr
31+
// CHECK: %[[L1:[_.i0-9]+]] = alloca <vscale x 16 x i8>, align 16
32+
// CHECK: %{{.*}} = alloca [16 x i8], align 1
33+
// CHECK: store <vscale x 16 x i8> poison, ptr %[[L1]], align 16
34+
// CHECK: %[[L2:[_.i0-9]+]] = load <vscale x 16 x i8>, ptr %[[L1]], align 16
35+
// CHECK: %{{.*}} = call <vscale x 16 x i8> @llvm.vector.insert.nxv16i8.v16i8(<vscale x 16 x i8> %[[L2]], <16 x i8> %{{.*}}, i64 0)
36+
37+
#[inline(always)]
38+
#[target_feature(enable = "sve")]
39+
pub fn svdupq_n_s8(
40+
x0: i8,
41+
x1: i8,
42+
x2: i8,
43+
x3: i8,
44+
x4: i8,
45+
x5: i8,
46+
x6: i8,
47+
x7: i8,
48+
x8: i8,
49+
x9: i8,
50+
x10: i8,
51+
x11: i8,
52+
x12: i8,
53+
x13: i8,
54+
x14: i8,
55+
x15: i8,
56+
) -> svint8_t {
57+
unsafe extern "unadjusted" {
58+
#[cfg_attr(
59+
target_arch = "aarch64",
60+
link_name = "llvm.experimental.vector.insert.nxv16i8.v16i8"
61+
)]
62+
fn _svdupq_n_s8(op0: svint8_t, op1: int8x16_t, idx: i64) -> svint8_t;
63+
}
64+
unsafe {
65+
_svdupq_n_s8(
66+
svundef_s8(),
67+
transmute([x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15]),
68+
0,
69+
)
70+
}
71+
}
72+
73+
#[target_feature(enable = "sve")]
74+
unsafe fn test_ffr() {
75+
svdupq_n_s8(1i8, 0i8, 1i8, 0i8, 1i8, 0i8, 1i8, 0i8, 1i8, 0i8, 1i8, 0i8, 1i8, 0i8, 1i8, 0i8);
76+
}
77+
78+
fn main() {
79+
unsafe { test_ffr() }
80+
}

0 commit comments

Comments
 (0)