Skip to content

Commit 95e7b35

Browse files
committed
mono: require target feature for scalable vectors
Scalable vector types only work with the relevant target features enabled, so require this for any function with the types in its signature.
1 parent 86e1b7f commit 95e7b35

File tree

6 files changed

+186
-51
lines changed

6 files changed

+186
-51
lines changed

compiler/rustc_monomorphize/messages.ftl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ monomorphize_abi_error_disabled_vector_type =
22
this function {$is_call ->
33
[true] call
44
*[false] definition
5-
} uses SIMD vector type `{$ty}` which (with the chosen ABI) requires the `{$required_feature}` target feature, which is not enabled{$is_call ->
5+
} uses {$is_scalable ->
6+
[true] scalable
7+
*[false] SIMD
8+
} vector type `{$ty}` which (with the chosen ABI) requires the `{$required_feature}` target feature, which is not enabled{$is_call ->
69
[true] {" "}in the caller
710
*[false] {""}
811
}

compiler/rustc_monomorphize/src/errors.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ pub(crate) struct AbiErrorDisabledVectorType<'a> {
7878
pub ty: Ty<'a>,
7979
/// Whether this is a problem at a call site or at a declaration.
8080
pub is_call: bool,
81+
/// Whether this is a problem with a fixed length vector or a scalable vector
82+
pub is_scalable: bool,
8183
}
8284

8385
#[derive(Diagnostic)]

compiler/rustc_monomorphize/src/mono_checks/abi_check.rs

Lines changed: 71 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,37 @@ use rustc_target::callconv::{FnAbi, PassMode};
1010

1111
use crate::errors;
1212

13-
fn uses_vector_registers(mode: &PassMode, repr: &BackendRepr) -> bool {
13+
/// Are vector registers used?
14+
enum UsesVectorRegisters {
15+
/// e.g. `neon`
16+
FixedVector,
17+
/// e.g. `sve`
18+
ScalableVector,
19+
No,
20+
}
21+
22+
/// Determines whether the combination of `mode` and `repr` will use fixed vector registers,
23+
/// scalable vector registers or no vector registers.
24+
fn uses_vector_registers(mode: &PassMode, repr: &BackendRepr) -> UsesVectorRegisters {
1425
match mode {
15-
PassMode::Ignore | PassMode::Indirect { .. } => false,
16-
PassMode::Cast { pad_i32: _, cast } => {
17-
cast.prefix.iter().any(|r| r.is_some_and(|x| x.kind == RegKind::Vector))
18-
|| cast.rest.unit.kind == RegKind::Vector
26+
PassMode::Ignore | PassMode::Indirect { .. } => UsesVectorRegisters::No,
27+
PassMode::Cast { pad_i32: _, cast }
28+
if cast.prefix.iter().any(|r| r.is_some_and(|x| x.kind == RegKind::Vector))
29+
|| cast.rest.unit.kind == RegKind::Vector =>
30+
{
31+
UsesVectorRegisters::FixedVector
32+
}
33+
PassMode::Direct(..) | PassMode::Pair(..)
34+
if matches!(repr, BackendRepr::SimdVector { .. }) =>
35+
{
36+
UsesVectorRegisters::FixedVector
1937
}
20-
PassMode::Direct(..) | PassMode::Pair(..) => matches!(repr, BackendRepr::SimdVector { .. }),
38+
PassMode::Direct(..) | PassMode::Pair(..)
39+
if matches!(repr, BackendRepr::ScalableVector { .. }) =>
40+
{
41+
UsesVectorRegisters::ScalableVector
42+
}
43+
_ => UsesVectorRegisters::No,
2144
}
2245
}
2346

@@ -32,37 +55,60 @@ fn do_check_simd_vector_abi<'tcx>(
3255
is_call: bool,
3356
loc: impl Fn() -> (Span, HirId),
3457
) {
35-
let feature_def = tcx.sess.target.features_for_correct_vector_abi();
3658
let codegen_attrs = tcx.codegen_fn_attrs(def_id);
3759
let have_feature = |feat: Symbol| {
38-
tcx.sess.unstable_target_features.contains(&feat)
39-
|| codegen_attrs.target_features.iter().any(|x| x.name == feat)
60+
let target_feats = tcx.sess.unstable_target_features.contains(&feat);
61+
let fn_feats = codegen_attrs.target_features.iter().any(|x| x.name == feat);
62+
target_feats || fn_feats
4063
};
4164
for arg_abi in abi.args.iter().chain(std::iter::once(&abi.ret)) {
4265
let size = arg_abi.layout.size;
43-
if uses_vector_registers(&arg_abi.mode, &arg_abi.layout.backend_repr) {
44-
// Find the first feature that provides at least this vector size.
45-
let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) {
46-
Some((_, feature)) => feature,
47-
None => {
66+
match uses_vector_registers(&arg_abi.mode, &arg_abi.layout.backend_repr) {
67+
UsesVectorRegisters::FixedVector => {
68+
let feature_def = tcx.sess.target.features_for_correct_fixed_length_vector_abi();
69+
// Find the first feature that provides at least this vector size.
70+
let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) {
71+
Some((_, feature)) => feature,
72+
None => {
73+
let (span, _hir_id) = loc();
74+
tcx.dcx().emit_err(errors::AbiErrorUnsupportedVectorType {
75+
span,
76+
ty: arg_abi.layout.ty,
77+
is_call,
78+
});
79+
continue;
80+
}
81+
};
82+
if !have_feature(Symbol::intern(feature)) {
4883
let (span, _hir_id) = loc();
49-
tcx.dcx().emit_err(errors::AbiErrorUnsupportedVectorType {
84+
tcx.dcx().emit_err(errors::AbiErrorDisabledVectorType {
5085
span,
86+
required_feature: feature,
5187
ty: arg_abi.layout.ty,
5288
is_call,
89+
is_scalable: false,
5390
});
91+
}
92+
}
93+
UsesVectorRegisters::ScalableVector => {
94+
let Some(required_feature) =
95+
tcx.sess.target.features_for_correct_scalable_vector_abi()
96+
else {
5497
continue;
98+
};
99+
if !have_feature(Symbol::intern(required_feature)) {
100+
let (span, _) = loc();
101+
tcx.dcx().emit_err(errors::AbiErrorDisabledVectorType {
102+
span,
103+
required_feature,
104+
ty: arg_abi.layout.ty,
105+
is_call,
106+
is_scalable: true,
107+
});
55108
}
56-
};
57-
if !have_feature(Symbol::intern(feature)) {
58-
// Emit error.
59-
let (span, _hir_id) = loc();
60-
tcx.dcx().emit_err(errors::AbiErrorDisabledVectorType {
61-
span,
62-
required_feature: feature,
63-
ty: arg_abi.layout.ty,
64-
is_call,
65-
});
109+
}
110+
UsesVectorRegisters::No => {
111+
continue;
66112
}
67113
}
68114
}

compiler/rustc_target/src/target_features.rs

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -863,17 +863,22 @@ pub fn all_rust_features() -> impl Iterator<Item = (&'static str, Stability)> {
863863
// These arrays represent the least-constraining feature that is required for vector types up to a
864864
// certain size to have their "proper" ABI on each architecture.
865865
// Note that they must be kept sorted by vector size.
866-
const X86_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
866+
const X86_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
867867
&[(128, "sse"), (256, "avx"), (512, "avx512f")]; // FIXME: might need changes for AVX10.
868-
const AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")];
868+
const AARCH64_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
869+
&[(128, "neon")];
869870

870871
// We might want to add "helium" too.
871-
const ARM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")];
872+
const ARM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
873+
&[(128, "neon")];
872874

873-
const POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "altivec")];
874-
const WASM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "simd128")];
875-
const S390X_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vector")];
876-
const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[
875+
const POWERPC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
876+
&[(128, "altivec")];
877+
const WASM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
878+
&[(128, "simd128")];
879+
const S390X_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
880+
&[(128, "vector")];
881+
const RISCV_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = &[
877882
(32, "zvl32b"),
878883
(64, "zvl64b"),
879884
(128, "zvl128b"),
@@ -888,13 +893,16 @@ const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[
888893
(65536, "zvl65536b"),
889894
];
890895
// Always error on SPARC, as the necessary target features cannot be enabled in Rust at the moment.
891-
const SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(64, "vis")*/];
896+
const SPARC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
897+
&[/*(64, "vis")*/];
892898

893-
const HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
899+
const HEXAGON_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
894900
&[/*(512, "hvx-length64b"),*/ (1024, "hvx-length128b")];
895-
const MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "msa")];
896-
const CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vdspv1")];
897-
const LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
901+
const MIPS_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
902+
&[(128, "msa")];
903+
const CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
904+
&[(128, "vdspv1")];
905+
const LOONGARCH_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
898906
&[(128, "lsx"), (256, "lasx")];
899907

900908
#[derive(Copy, Clone, Debug)]
@@ -927,27 +935,38 @@ impl Target {
927935
}
928936
}
929937

930-
pub fn features_for_correct_vector_abi(&self) -> &'static [(u64, &'static str)] {
938+
pub fn features_for_correct_fixed_length_vector_abi(&self) -> &'static [(u64, &'static str)] {
931939
match &*self.arch {
932-
"x86" | "x86_64" => X86_FEATURES_FOR_CORRECT_VECTOR_ABI,
933-
"aarch64" | "arm64ec" => AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI,
934-
"arm" => ARM_FEATURES_FOR_CORRECT_VECTOR_ABI,
935-
"powerpc" | "powerpc64" => POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI,
936-
"loongarch32" | "loongarch64" => LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI,
937-
"riscv32" | "riscv64" => RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI,
938-
"wasm32" | "wasm64" => WASM_FEATURES_FOR_CORRECT_VECTOR_ABI,
939-
"s390x" => S390X_FEATURES_FOR_CORRECT_VECTOR_ABI,
940-
"sparc" | "sparc64" => SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI,
941-
"hexagon" => HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI,
942-
"mips" | "mips32r6" | "mips64" | "mips64r6" => MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI,
940+
"x86" | "x86_64" => X86_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
941+
"aarch64" | "arm64ec" => AARCH64_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
942+
"arm" => ARM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
943+
"powerpc" | "powerpc64" => POWERPC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
944+
"loongarch32" | "loongarch64" => LOONGARCH_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
945+
"riscv32" | "riscv64" => RISCV_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
946+
"wasm32" | "wasm64" => WASM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
947+
"s390x" => S390X_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
948+
"sparc" | "sparc64" => SPARC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
949+
"hexagon" => HEXAGON_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
950+
"mips" | "mips32r6" | "mips64" | "mips64r6" => {
951+
MIPS_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI
952+
}
943953
"nvptx64" | "bpf" | "m68k" => &[], // no vector ABI
944-
"csky" => CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI,
954+
"csky" => CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
945955
// FIXME: for some tier3 targets, we are overly cautious and always give warnings
946956
// when passing args in vector registers.
947957
_ => &[],
948958
}
949959
}
950960

961+
pub fn features_for_correct_scalable_vector_abi(&self) -> Option<&'static str> {
962+
match &*self.arch {
963+
"aarch64" | "arm64ec" => Some("sve"),
964+
"riscv32" | "riscv64" => todo!(),
965+
// Other targets have no scalable vectors.
966+
_ => None,
967+
}
968+
}
969+
951970
pub fn tied_target_features(&self) -> &'static [&'static [&'static str]] {
952971
match &*self.arch {
953972
"aarch64" | "arm64ec" => AARCH64_TIED_FEATURES,
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//@ build-fail
2+
//@ compile-flags: --crate-type=lib
3+
//@ only-aarch64
4+
#![allow(incomplete_features, internal_features)]
5+
#![feature(
6+
simd_ffi,
7+
rustc_attrs,
8+
link_llvm_intrinsics
9+
)]
10+
11+
#[derive(Copy, Clone)]
12+
#[rustc_scalable_vector(4)]
13+
#[allow(non_camel_case_types)]
14+
pub struct svint32_t(i32);
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+
//~^ WARN: `extern` block uses type `svint32_t`, which is not FFI-safe
23+
}
24+
unsafe { _svdup_n_s32(op) }
25+
}
26+
27+
pub fn non_annotated_callee(x: svint32_t) {}
28+
//~^ ERROR: this function definition uses scalable vector type `svint32_t`
29+
30+
#[target_feature(enable = "sve")]
31+
pub fn annotated_callee(x: svint32_t) {} // okay!
32+
33+
#[target_feature(enable = "sve")]
34+
pub fn caller() {
35+
unsafe {
36+
let a = svdup_n_s32(42);
37+
non_annotated_callee(a);
38+
annotated_callee(a);
39+
}
40+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
warning: `extern` block uses type `svint32_t`, which is not FFI-safe
2+
--> $DIR/require-target-feature.rs:21:37
3+
|
4+
LL | fn _svdup_n_s32(op: i32) -> svint32_t;
5+
| ^^^^^^^^^ not FFI-safe
6+
|
7+
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
8+
= note: this struct has unspecified layout
9+
note: the type is defined here
10+
--> $DIR/require-target-feature.rs:14:1
11+
|
12+
LL | pub struct svint32_t(i32);
13+
| ^^^^^^^^^^^^^^^^^^^^
14+
= note: `#[warn(improper_ctypes)]` on by default
15+
16+
error: this function definition uses scalable vector type `svint32_t` which (with the chosen ABI) requires the `sve` target feature, which is not enabled
17+
--> $DIR/require-target-feature.rs:27:1
18+
|
19+
LL | pub fn non_annotated_callee(x: svint32_t) {}
20+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
21+
|
22+
= help: consider enabling it globally (`-C target-feature=+sve`) or locally (`#[target_feature(enable="sve")]`)
23+
24+
error: aborting due to 1 previous error; 1 warning emitted
25+

0 commit comments

Comments
 (0)