Skip to content

Commit 0ed0434

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 cdd2983 commit 0ed0434

File tree

6 files changed

+176
-51
lines changed

6 files changed

+176
-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
@@ -75,6 +75,8 @@ pub(crate) struct AbiErrorDisabledVectorType<'a> {
7575
pub ty: Ty<'a>,
7676
/// Whether this is a problem at a call site or at a declaration.
7777
pub is_call: bool,
78+
/// Whether this is a problem with a fixed length vector or a scalable vector
79+
pub is_scalable: bool,
7880
}
7981

8082
#[derive(Diagnostic)]

compiler/rustc_monomorphize/src/mono_checks/abi_check.rs

Lines changed: 75 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,64 @@ 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();
58+
tracing::debug!(?def_id);
3659
let codegen_attrs = tcx.codegen_fn_attrs(def_id);
3760
let have_feature = |feat: Symbol| {
38-
tcx.sess.unstable_target_features.contains(&feat)
39-
|| codegen_attrs.target_features.iter().any(|x| x.name == feat)
61+
let target_feats = tcx.sess.unstable_target_features.contains(&feat);
62+
let fn_feats = codegen_attrs.target_features.iter().any(|x| x.name == feat);
63+
tracing::debug!(?target_feats, ?fn_feats);
64+
target_feats || fn_feats
4065
};
4166
for arg_abi in abi.args.iter().chain(std::iter::once(&abi.ret)) {
67+
tracing::debug!(?arg_abi);
4268
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 => {
69+
match uses_vector_registers(&arg_abi.mode, &arg_abi.layout.backend_repr) {
70+
UsesVectorRegisters::FixedVector => {
71+
let feature_def = tcx.sess.target.features_for_correct_fixed_length_vector_abi();
72+
// Find the first feature that provides at least this vector size.
73+
let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) {
74+
Some((_, feature)) => feature,
75+
None => {
76+
let (span, _hir_id) = loc();
77+
tcx.dcx().emit_err(errors::AbiErrorUnsupportedVectorType {
78+
span,
79+
ty: arg_abi.layout.ty,
80+
is_call,
81+
});
82+
continue;
83+
}
84+
};
85+
if !have_feature(Symbol::intern(feature)) {
4886
let (span, _hir_id) = loc();
49-
tcx.dcx().emit_err(errors::AbiErrorUnsupportedVectorType {
87+
tcx.dcx().emit_err(errors::AbiErrorDisabledVectorType {
5088
span,
89+
required_feature: feature,
5190
ty: arg_abi.layout.ty,
5291
is_call,
92+
is_scalable: false,
5393
});
94+
}
95+
}
96+
UsesVectorRegisters::ScalableVector => {
97+
let Some(required_feature) =
98+
tcx.sess.target.features_for_correct_scalable_vector_abi()
99+
else {
54100
continue;
101+
};
102+
tracing::debug!(?required_feature);
103+
if !have_feature(Symbol::intern(required_feature)) {
104+
let (span, _) = loc();
105+
tcx.dcx().emit_err(errors::AbiErrorDisabledVectorType {
106+
span,
107+
required_feature,
108+
ty: arg_abi.layout.ty,
109+
is_call,
110+
is_scalable: true,
111+
});
55112
}
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-
});
113+
}
114+
UsesVectorRegisters::No => {
115+
continue;
66116
}
67117
}
68118
}

compiler/rustc_target/src/target_features.rs

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

804805
// We might want to add "helium" too.
805-
const ARM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")];
806+
const ARM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
807+
&[(128, "neon")];
806808

807-
const POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "altivec")];
808-
const WASM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "simd128")];
809-
const S390X_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vector")];
810-
const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[
809+
const POWERPC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
810+
&[(128, "altivec")];
811+
const WASM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
812+
&[(128, "simd128")];
813+
const S390X_FEATURES_FOR_CORRECT_FIXED_LEGNTH_VECTOR_ABI: &'static [(u64, &'static str)] =
814+
&[(128, "vector")];
815+
const RISCV_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = &[
811816
(32, "zvl32b"),
812817
(64, "zvl64b"),
813818
(128, "zvl128b"),
@@ -822,13 +827,16 @@ const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[
822827
(65536, "zvl65536b"),
823828
];
824829
// Always error on SPARC, as the necessary target features cannot be enabled in Rust at the moment.
825-
const SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(64, "vis")*/];
830+
const SPARC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
831+
&[/*(64, "vis")*/];
826832

827-
const HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
833+
const HEXAGON_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
828834
&[/*(512, "hvx-length64b"),*/ (1024, "hvx-length128b")];
829-
const MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "msa")];
830-
const CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vdspv1")];
831-
const LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
835+
const MIPS_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
836+
&[(128, "msa")];
837+
const CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
838+
&[(128, "vdspv1")];
839+
const LOONGARCH_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
832840
&[(128, "lsx"), (256, "lasx")];
833841

834842
#[derive(Copy, Clone, Debug)]
@@ -860,27 +868,38 @@ impl Target {
860868
}
861869
}
862870

863-
pub fn features_for_correct_vector_abi(&self) -> &'static [(u64, &'static str)] {
871+
pub fn features_for_correct_fixed_length_vector_abi(&self) -> &'static [(u64, &'static str)] {
864872
match &*self.arch {
865-
"x86" | "x86_64" => X86_FEATURES_FOR_CORRECT_VECTOR_ABI,
866-
"aarch64" | "arm64ec" => AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI,
867-
"arm" => ARM_FEATURES_FOR_CORRECT_VECTOR_ABI,
868-
"powerpc" | "powerpc64" => POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI,
869-
"loongarch32" | "loongarch64" => LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI,
870-
"riscv32" | "riscv64" => RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI,
871-
"wasm32" | "wasm64" => WASM_FEATURES_FOR_CORRECT_VECTOR_ABI,
872-
"s390x" => S390X_FEATURES_FOR_CORRECT_VECTOR_ABI,
873-
"sparc" | "sparc64" => SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI,
874-
"hexagon" => HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI,
875-
"mips" | "mips32r6" | "mips64" | "mips64r6" => MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI,
873+
"x86" | "x86_64" => X86_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
874+
"aarch64" | "arm64ec" => AARCH64_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
875+
"arm" => ARM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
876+
"powerpc" | "powerpc64" => POWERPC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
877+
"loongarch32" | "loongarch64" => LOONGARCH_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
878+
"riscv32" | "riscv64" => RISCV_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
879+
"wasm32" | "wasm64" => WASM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
880+
"s390x" => S390X_FEATURES_FOR_CORRECT_FIXED_LEGNTH_VECTOR_ABI,
881+
"sparc" | "sparc64" => SPARC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
882+
"hexagon" => HEXAGON_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
883+
"mips" | "mips32r6" | "mips64" | "mips64r6" => {
884+
MIPS_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI
885+
}
876886
"bpf" | "m68k" => &[], // no vector ABI
877-
"csky" => CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI,
887+
"csky" => CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
878888
// FIXME: for some tier3 targets, we are overly cautious and always give warnings
879889
// when passing args in vector registers.
880890
_ => &[],
881891
}
882892
}
883893

894+
pub fn features_for_correct_scalable_vector_abi(&self) -> Option<&'static str> {
895+
match &*self.arch {
896+
"aarch64" | "arm64ec" => Some("sve"),
897+
"riscv32" | "riscv64" => todo!(),
898+
// Other targets have no scalable vectors.
899+
_ => None,
900+
}
901+
}
902+
884903
pub fn tied_target_features(&self) -> &'static [&'static [&'static str]] {
885904
match &*self.arch {
886905
"aarch64" | "arm64ec" => AARCH64_TIED_FEATURES,
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//@ build-fail
2+
//@ compile-flags: --crate-type=lib
3+
#![allow(incomplete_features, internal_features)]
4+
#![feature(
5+
repr_simd,
6+
repr_scalable,
7+
simd_ffi,
8+
link_llvm_intrinsics
9+
)]
10+
11+
#[derive(Copy, Clone)]
12+
#[repr(simd, scalable(4))]
13+
#[allow(non_camel_case_types)]
14+
pub struct svint32_t {
15+
_ty: [i32],
16+
}
17+
18+
#[inline(never)]
19+
#[target_feature(enable = "sve")]
20+
pub unsafe fn svdup_n_s32(op: i32) -> svint32_t {
21+
extern "C" {
22+
#[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.dup.x.nxv4i32")]
23+
fn _svdup_n_s32(op: i32) -> svint32_t;
24+
}
25+
unsafe { _svdup_n_s32(op) }
26+
}
27+
28+
pub fn non_annotated_callee(x: svint32_t) {}
29+
//~^ ERROR: this function definition uses scalable vector type `svint32_t`
30+
31+
#[target_feature(enable = "sve")]
32+
pub fn annotated_callee(x: svint32_t) {} // okay!
33+
34+
#[target_feature(enable = "sve")]
35+
pub fn caller() {
36+
unsafe {
37+
let a = svdup_n_s32(42);
38+
non_annotated_callee(a);
39+
annotated_callee(a);
40+
}
41+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: this function definition uses scalable vector type `svint32_t` which (with the chosen ABI) requires the `sve` target feature, which is not enabled
2+
--> $DIR/require-target-feature.rs:28:1
3+
|
4+
LL | pub fn non_annotated_callee(x: svint32_t) {}
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
6+
|
7+
= help: consider enabling it globally (`-C target-feature=+sve`) or locally (`#[target_feature(enable="sve")]`)
8+
9+
error: aborting due to 1 previous error
10+

0 commit comments

Comments
 (0)