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.
This commit is contained in:
parent
4185e9f2ec
commit
5f27abdbc8
6 changed files with 190 additions and 55 deletions
|
|
@ -2,7 +2,10 @@ monomorphize_abi_error_disabled_vector_type =
|
|||
this function {$is_call ->
|
||||
[true] call
|
||||
*[false] definition
|
||||
} uses SIMD vector type `{$ty}` which (with the chosen ABI) requires the `{$required_feature}` target feature, which is not enabled{$is_call ->
|
||||
} uses {$is_scalable ->
|
||||
[true] scalable
|
||||
*[false] SIMD
|
||||
} vector type `{$ty}` which (with the chosen ABI) requires the `{$required_feature}` target feature, which is not enabled{$is_call ->
|
||||
[true] {" "}in the caller
|
||||
*[false] {""}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,6 +78,8 @@ pub(crate) struct AbiErrorDisabledVectorType<'a> {
|
|||
pub ty: Ty<'a>,
|
||||
/// Whether this is a problem at a call site or at a declaration.
|
||||
pub is_call: bool,
|
||||
/// Whether this is a problem with a fixed length vector or a scalable vector
|
||||
pub is_scalable: bool,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
|||
|
|
@ -10,14 +10,37 @@ use rustc_target::callconv::{FnAbi, PassMode};
|
|||
|
||||
use crate::errors;
|
||||
|
||||
fn uses_vector_registers(mode: &PassMode, repr: &BackendRepr) -> bool {
|
||||
/// Are vector registers used?
|
||||
enum UsesVectorRegisters {
|
||||
/// e.g. `neon`
|
||||
FixedVector,
|
||||
/// e.g. `sve`
|
||||
ScalableVector,
|
||||
No,
|
||||
}
|
||||
|
||||
/// Determines whether the combination of `mode` and `repr` will use fixed vector registers,
|
||||
/// scalable vector registers or no vector registers.
|
||||
fn passes_vectors_by_value(mode: &PassMode, repr: &BackendRepr) -> UsesVectorRegisters {
|
||||
match mode {
|
||||
PassMode::Ignore | PassMode::Indirect { .. } => false,
|
||||
PassMode::Cast { pad_i32: _, cast } => {
|
||||
cast.prefix.iter().any(|r| r.is_some_and(|x| x.kind == RegKind::Vector))
|
||||
|| cast.rest.unit.kind == RegKind::Vector
|
||||
PassMode::Ignore | PassMode::Indirect { .. } => UsesVectorRegisters::No,
|
||||
PassMode::Cast { pad_i32: _, cast }
|
||||
if cast.prefix.iter().any(|r| r.is_some_and(|x| x.kind == RegKind::Vector))
|
||||
|| cast.rest.unit.kind == RegKind::Vector =>
|
||||
{
|
||||
UsesVectorRegisters::FixedVector
|
||||
}
|
||||
PassMode::Direct(..) | PassMode::Pair(..) => matches!(repr, BackendRepr::SimdVector { .. }),
|
||||
PassMode::Direct(..) | PassMode::Pair(..)
|
||||
if matches!(repr, BackendRepr::SimdVector { .. }) =>
|
||||
{
|
||||
UsesVectorRegisters::FixedVector
|
||||
}
|
||||
PassMode::Direct(..) | PassMode::Pair(..)
|
||||
if matches!(repr, BackendRepr::ScalableVector { .. }) =>
|
||||
{
|
||||
UsesVectorRegisters::ScalableVector
|
||||
}
|
||||
_ => UsesVectorRegisters::No,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -32,37 +55,60 @@ fn do_check_simd_vector_abi<'tcx>(
|
|||
is_call: bool,
|
||||
loc: impl Fn() -> (Span, HirId),
|
||||
) {
|
||||
let feature_def = tcx.sess.target.features_for_correct_vector_abi();
|
||||
let codegen_attrs = tcx.codegen_fn_attrs(def_id);
|
||||
let have_feature = |feat: Symbol| {
|
||||
tcx.sess.unstable_target_features.contains(&feat)
|
||||
|| codegen_attrs.target_features.iter().any(|x| x.name == feat)
|
||||
let target_feats = tcx.sess.unstable_target_features.contains(&feat);
|
||||
let fn_feats = codegen_attrs.target_features.iter().any(|x| x.name == feat);
|
||||
target_feats || fn_feats
|
||||
};
|
||||
for arg_abi in abi.args.iter().chain(std::iter::once(&abi.ret)) {
|
||||
let size = arg_abi.layout.size;
|
||||
if uses_vector_registers(&arg_abi.mode, &arg_abi.layout.backend_repr) {
|
||||
// Find the first feature that provides at least this vector size.
|
||||
let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) {
|
||||
Some((_, feature)) => feature,
|
||||
None => {
|
||||
match passes_vectors_by_value(&arg_abi.mode, &arg_abi.layout.backend_repr) {
|
||||
UsesVectorRegisters::FixedVector => {
|
||||
let feature_def = tcx.sess.target.features_for_correct_fixed_length_vector_abi();
|
||||
// Find the first feature that provides at least this vector size.
|
||||
let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) {
|
||||
Some((_, feature)) => feature,
|
||||
None => {
|
||||
let (span, _hir_id) = loc();
|
||||
tcx.dcx().emit_err(errors::AbiErrorUnsupportedVectorType {
|
||||
span,
|
||||
ty: arg_abi.layout.ty,
|
||||
is_call,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
};
|
||||
if !feature.is_empty() && !have_feature(Symbol::intern(feature)) {
|
||||
let (span, _hir_id) = loc();
|
||||
tcx.dcx().emit_err(errors::AbiErrorUnsupportedVectorType {
|
||||
tcx.dcx().emit_err(errors::AbiErrorDisabledVectorType {
|
||||
span,
|
||||
required_feature: feature,
|
||||
ty: arg_abi.layout.ty,
|
||||
is_call,
|
||||
is_scalable: false,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
};
|
||||
if !feature.is_empty() && !have_feature(Symbol::intern(feature)) {
|
||||
// Emit error.
|
||||
let (span, _hir_id) = loc();
|
||||
tcx.dcx().emit_err(errors::AbiErrorDisabledVectorType {
|
||||
span,
|
||||
required_feature: feature,
|
||||
ty: arg_abi.layout.ty,
|
||||
is_call,
|
||||
});
|
||||
}
|
||||
UsesVectorRegisters::ScalableVector => {
|
||||
let Some(required_feature) =
|
||||
tcx.sess.target.features_for_correct_scalable_vector_abi()
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
if !required_feature.is_empty() && !have_feature(Symbol::intern(required_feature)) {
|
||||
let (span, _) = loc();
|
||||
tcx.dcx().emit_err(errors::AbiErrorDisabledVectorType {
|
||||
span,
|
||||
required_feature,
|
||||
ty: arg_abi.layout.ty,
|
||||
is_call,
|
||||
is_scalable: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
UsesVectorRegisters::No => {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -911,18 +911,24 @@ pub fn all_rust_features() -> impl Iterator<Item = (&'static str, Stability)> {
|
|||
// These arrays represent the least-constraining feature that is required for vector types up to a
|
||||
// certain size to have their "proper" ABI on each architecture.
|
||||
// Note that they must be kept sorted by vector size.
|
||||
const X86_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
|
||||
const X86_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
|
||||
&[(128, "sse"), (256, "avx"), (512, "avx512f")]; // FIXME: might need changes for AVX10.
|
||||
const AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")];
|
||||
const AARCH64_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
|
||||
&[(128, "neon")];
|
||||
|
||||
// We might want to add "helium" too.
|
||||
const ARM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")];
|
||||
const ARM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
|
||||
&[(128, "neon")];
|
||||
|
||||
const AMDGPU_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(1024, "")];
|
||||
const POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "altivec")];
|
||||
const WASM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "simd128")];
|
||||
const S390X_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vector")];
|
||||
const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[
|
||||
const AMDGPU_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
|
||||
&[(1024, "")];
|
||||
const POWERPC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
|
||||
&[(128, "altivec")];
|
||||
const WASM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
|
||||
&[(128, "simd128")];
|
||||
const S390X_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
|
||||
&[(128, "vector")];
|
||||
const RISCV_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = &[
|
||||
(32, "zvl32b"),
|
||||
(64, "zvl64b"),
|
||||
(128, "zvl128b"),
|
||||
|
|
@ -937,13 +943,16 @@ const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[
|
|||
(65536, "zvl65536b"),
|
||||
];
|
||||
// Always error on SPARC, as the necessary target features cannot be enabled in Rust at the moment.
|
||||
const SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(64, "vis")*/];
|
||||
const SPARC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
|
||||
&[/*(64, "vis")*/];
|
||||
|
||||
const HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
|
||||
const HEXAGON_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
|
||||
&[/*(512, "hvx-length64b"),*/ (1024, "hvx-length128b")];
|
||||
const MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "msa")];
|
||||
const CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vdspv1")];
|
||||
const LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
|
||||
const MIPS_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
|
||||
&[(128, "msa")];
|
||||
const CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
|
||||
&[(128, "vdspv1")];
|
||||
const LOONGARCH_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
|
||||
&[(128, "lsx"), (256, "lasx")];
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
|
@ -982,24 +991,26 @@ impl Target {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn features_for_correct_vector_abi(&self) -> &'static [(u64, &'static str)] {
|
||||
pub fn features_for_correct_fixed_length_vector_abi(&self) -> &'static [(u64, &'static str)] {
|
||||
match &self.arch {
|
||||
Arch::X86 | Arch::X86_64 => X86_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
Arch::AArch64 | Arch::Arm64EC => AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
Arch::Arm => ARM_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
Arch::PowerPC | Arch::PowerPC64 => POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
Arch::LoongArch32 | Arch::LoongArch64 => LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
Arch::RiscV32 | Arch::RiscV64 => RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
Arch::Wasm32 | Arch::Wasm64 => WASM_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
Arch::S390x => S390X_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
Arch::Sparc | Arch::Sparc64 => SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
Arch::Hexagon => HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => {
|
||||
MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI
|
||||
Arch::X86 | Arch::X86_64 => X86_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
|
||||
Arch::AArch64 | Arch::Arm64EC => AARCH64_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
|
||||
Arch::Arm => ARM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
|
||||
Arch::PowerPC | Arch::PowerPC64 => POWERPC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
|
||||
Arch::LoongArch32 | Arch::LoongArch64 => {
|
||||
LOONGARCH_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI
|
||||
}
|
||||
Arch::AmdGpu => AMDGPU_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
Arch::RiscV32 | Arch::RiscV64 => RISCV_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
|
||||
Arch::Wasm32 | Arch::Wasm64 => WASM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
|
||||
Arch::S390x => S390X_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
|
||||
Arch::Sparc | Arch::Sparc64 => SPARC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
|
||||
Arch::Hexagon => HEXAGON_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
|
||||
Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => {
|
||||
MIPS_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI
|
||||
}
|
||||
Arch::AmdGpu => AMDGPU_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
|
||||
Arch::Nvptx64 | Arch::Bpf | Arch::M68k => &[], // no vector ABI
|
||||
Arch::CSky => CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
Arch::CSky => CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
|
||||
// FIXME: for some tier3 targets, we are overly cautious and always give warnings
|
||||
// when passing args in vector registers.
|
||||
Arch::Avr
|
||||
|
|
@ -1011,6 +1022,14 @@ impl Target {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn features_for_correct_scalable_vector_abi(&self) -> Option<&'static str> {
|
||||
match &self.arch {
|
||||
Arch::AArch64 | Arch::Arm64EC => Some("sve"),
|
||||
// Other targets have no scalable vectors or they are unimplemented.
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tied_target_features(&self) -> &'static [&'static [&'static str]] {
|
||||
match &self.arch {
|
||||
Arch::AArch64 | Arch::Arm64EC => AARCH64_TIED_FEATURES,
|
||||
|
|
|
|||
40
tests/ui/scalable-vectors/require-target-feature.rs
Normal file
40
tests/ui/scalable-vectors/require-target-feature.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
//@ build-fail
|
||||
//@ compile-flags: --crate-type=lib
|
||||
//@ only-aarch64
|
||||
#![allow(incomplete_features, internal_features)]
|
||||
#![feature(
|
||||
simd_ffi,
|
||||
rustc_attrs,
|
||||
link_llvm_intrinsics
|
||||
)]
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[rustc_scalable_vector(4)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct svint32_t(i32);
|
||||
|
||||
#[inline(never)]
|
||||
#[target_feature(enable = "sve")]
|
||||
pub unsafe fn svdup_n_s32(op: i32) -> svint32_t {
|
||||
extern "C" {
|
||||
#[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.dup.x.nxv4i32")]
|
||||
fn _svdup_n_s32(op: i32) -> svint32_t;
|
||||
//~^ WARN: `extern` block uses type `svint32_t`, which is not FFI-safe
|
||||
}
|
||||
unsafe { _svdup_n_s32(op) }
|
||||
}
|
||||
|
||||
pub fn non_annotated_callee(x: svint32_t) {}
|
||||
//~^ ERROR: this function definition uses scalable vector type `svint32_t`
|
||||
|
||||
#[target_feature(enable = "sve")]
|
||||
pub fn annotated_callee(x: svint32_t) {} // okay!
|
||||
|
||||
#[target_feature(enable = "sve")]
|
||||
pub fn caller() {
|
||||
unsafe {
|
||||
let a = svdup_n_s32(42);
|
||||
non_annotated_callee(a);
|
||||
annotated_callee(a);
|
||||
}
|
||||
}
|
||||
25
tests/ui/scalable-vectors/require-target-feature.stderr
Normal file
25
tests/ui/scalable-vectors/require-target-feature.stderr
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
warning: `extern` block uses type `svint32_t`, which is not FFI-safe
|
||||
--> $DIR/require-target-feature.rs:21:37
|
||||
|
|
||||
LL | fn _svdup_n_s32(op: i32) -> svint32_t;
|
||||
| ^^^^^^^^^ not FFI-safe
|
||||
|
|
||||
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
|
||||
= note: this struct has unspecified layout
|
||||
note: the type is defined here
|
||||
--> $DIR/require-target-feature.rs:14:1
|
||||
|
|
||||
LL | pub struct svint32_t(i32);
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
= note: `#[warn(improper_ctypes)]` on by default
|
||||
|
||||
error: this function definition uses scalable vector type `svint32_t` which (with the chosen ABI) requires the `sve` target feature, which is not enabled
|
||||
--> $DIR/require-target-feature.rs:27:1
|
||||
|
|
||||
LL | pub fn non_annotated_callee(x: svint32_t) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
||||
= help: consider enabling it globally (`-C target-feature=+sve`) or locally (`#[target_feature(enable="sve")]`)
|
||||
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue