Skip to content

Commit 8a0189a

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 b7bdb26 commit 8a0189a

File tree

6 files changed

+185
-51
lines changed

6 files changed

+185
-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: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -911,17 +911,22 @@ pub fn all_rust_features() -> impl Iterator<Item = (&'static str, Stability)> {
911911
// These arrays represent the least-constraining feature that is required for vector types up to a
912912
// certain size to have their "proper" ABI on each architecture.
913913
// Note that they must be kept sorted by vector size.
914-
const X86_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
914+
const X86_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
915915
&[(128, "sse"), (256, "avx"), (512, "avx512f")]; // FIXME: might need changes for AVX10.
916-
const AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")];
916+
const AARCH64_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
917+
&[(128, "neon")];
917918

918919
// We might want to add "helium" too.
919-
const ARM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")];
920+
const ARM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
921+
&[(128, "neon")];
920922

921-
const POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "altivec")];
922-
const WASM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "simd128")];
923-
const S390X_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vector")];
924-
const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[
923+
const POWERPC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
924+
&[(128, "altivec")];
925+
const WASM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
926+
&[(128, "simd128")];
927+
const S390X_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
928+
&[(128, "vector")];
929+
const RISCV_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = &[
925930
(32, "zvl32b"),
926931
(64, "zvl64b"),
927932
(128, "zvl128b"),
@@ -936,13 +941,16 @@ const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[
936941
(65536, "zvl65536b"),
937942
];
938943
// Always error on SPARC, as the necessary target features cannot be enabled in Rust at the moment.
939-
const SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(64, "vis")*/];
944+
const SPARC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
945+
&[/*(64, "vis")*/];
940946

941-
const HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
947+
const HEXAGON_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
942948
&[/*(512, "hvx-length64b"),*/ (1024, "hvx-length128b")];
943-
const MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "msa")];
944-
const CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vdspv1")];
945-
const LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
949+
const MIPS_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
950+
&[(128, "msa")];
951+
const CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
952+
&[(128, "vdspv1")];
953+
const LOONGARCH_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
946954
&[(128, "lsx"), (256, "lasx")];
947955

948956
#[derive(Copy, Clone, Debug)]
@@ -981,23 +989,25 @@ impl Target {
981989
}
982990
}
983991

984-
pub fn features_for_correct_vector_abi(&self) -> &'static [(u64, &'static str)] {
992+
pub fn features_for_correct_fixed_length_vector_abi(&self) -> &'static [(u64, &'static str)] {
985993
match &self.arch {
986-
Arch::X86 | Arch::X86_64 => X86_FEATURES_FOR_CORRECT_VECTOR_ABI,
987-
Arch::AArch64 | Arch::Arm64EC => AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI,
988-
Arch::Arm => ARM_FEATURES_FOR_CORRECT_VECTOR_ABI,
989-
Arch::PowerPC | Arch::PowerPC64 => POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI,
990-
Arch::LoongArch32 | Arch::LoongArch64 => LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI,
991-
Arch::RiscV32 | Arch::RiscV64 => RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI,
992-
Arch::Wasm32 | Arch::Wasm64 => WASM_FEATURES_FOR_CORRECT_VECTOR_ABI,
993-
Arch::S390x => S390X_FEATURES_FOR_CORRECT_VECTOR_ABI,
994-
Arch::Sparc | Arch::Sparc64 => SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI,
995-
Arch::Hexagon => HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI,
994+
Arch::X86 | Arch::X86_64 => X86_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
995+
Arch::AArch64 | Arch::Arm64EC => AARCH64_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
996+
Arch::Arm => ARM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
997+
Arch::PowerPC | Arch::PowerPC64 => POWERPC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
998+
Arch::LoongArch32 | Arch::LoongArch64 => {
999+
LOONGARCH_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI
1000+
}
1001+
Arch::RiscV32 | Arch::RiscV64 => RISCV_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1002+
Arch::Wasm32 | Arch::Wasm64 => WASM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1003+
Arch::S390x => S390X_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1004+
Arch::Sparc | Arch::Sparc64 => SPARC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1005+
Arch::Hexagon => HEXAGON_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
9961006
Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => {
997-
MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI
1007+
MIPS_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI
9981008
}
9991009
Arch::Nvptx64 | Arch::Bpf | Arch::M68k => &[], // no vector ABI
1000-
Arch::CSky => CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI,
1010+
Arch::CSky => CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
10011011
// FIXME: for some tier3 targets, we are overly cautious and always give warnings
10021012
// when passing args in vector registers.
10031013
Arch::AmdGpu
@@ -1010,6 +1020,14 @@ impl Target {
10101020
}
10111021
}
10121022

1023+
pub fn features_for_correct_scalable_vector_abi(&self) -> Option<&'static str> {
1024+
match &self.arch {
1025+
Arch::AArch64 | Arch::Arm64EC => Some("sve"),
1026+
// Other targets have no scalable vectors or they are unimplemented.
1027+
_ => None,
1028+
}
1029+
}
1030+
10131031
pub fn tied_target_features(&self) -> &'static [&'static [&'static str]] {
10141032
match &self.arch {
10151033
Arch::AArch64 | Arch::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)