Rollup merge of #152941 - RalfJung:abi-control, r=mati865

prefer actual ABI-controling fields over target.abi when making ABI decisions

We don't actually check that `abi` is consistent with the fields that control the ABI, e.g. one could set `llvm_abiname` to "ilp32e" on a riscv target without setting a matching `abi`. So, if we need to make actual decisions, better to use the source of truth we forward to LLVM than the informational string we forward to the user.

This is a breaking change for aarch64 JSON target specs: setting `abi` to "softfloat" is no longer enough; one has to also set `rustc_abi` to "softfloat". That is consistent with riscv and arm32, but it's still surprising. Cc @Darksonn in case this affects the Linux kernel.

Also see https://github.com/rust-lang/rust/pull/153035 which does something similar for PowerPC, and [Zulip](https://rust-lang.zulipchat.com/#narrow/channel/131828-t-compiler/topic/De-spaghettifying.20ABI.20controls/with/575095372). Happy to delay this PR if someone has a better idea.

Cc @folkertdev @workingjubilee
This commit is contained in:
Jonathan Brouwer
2026-03-03 07:14:11 +01:00
committed by GitHub
7 changed files with 37 additions and 28 deletions
+3 -3
View File
@@ -8,7 +8,7 @@
use rustc_middle::bug;
use rustc_middle::ty::Ty;
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
use rustc_target::spec::{Abi, Arch, Env};
use rustc_target::spec::{Arch, Env, RustcAbi};
use crate::builder::Builder;
use crate::llvm::{Type, Value};
@@ -272,7 +272,7 @@ fn emit_powerpc_va_arg<'ll, 'tcx>(
// Rust does not currently support any powerpc softfloat targets.
let target = &bx.cx.tcx.sess.target;
let is_soft_float_abi = target.abi == Abi::SoftFloat;
let is_soft_float_abi = target.rustc_abi == Some(RustcAbi::Softfloat);
assert!(!is_soft_float_abi);
// All instances of VaArgSafe are passed directly.
@@ -1077,7 +1077,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
AllowHigherAlign::Yes,
ForceRightAdjust::Yes,
),
Arch::RiscV32 if target.abi == Abi::Ilp32e => {
Arch::RiscV32 if target.llvm_abiname == "ilp32e" => {
// FIXME: clang manually adjusts the alignment for this ABI. It notes:
//
// > To be compatible with GCC's behaviors, we force arguments with
@@ -3,7 +3,7 @@
use rustc_abi::{BackendRepr, HasDataLayout, Primitive, TyAbiInterface};
use crate::callconv::{ArgAbi, FnAbi, Reg, RegKind, Uniform};
use crate::spec::{Abi, HasTargetSpec, Target};
use crate::spec::{HasTargetSpec, RustcAbi, Target};
/// Indicates the variant of the AArch64 ABI we are compiling for.
/// Used to accommodate Apple and Microsoft's deviations from the usual AAPCS ABI.
@@ -34,7 +34,7 @@ fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Opti
RegKind::Integer => false,
// The softfloat ABI treats floats like integers, so they
// do not get homogeneous aggregate treatment.
RegKind::Float => cx.target_spec().abi != Abi::SoftFloat,
RegKind::Float => cx.target_spec().rustc_abi != Some(RustcAbi::Softfloat),
RegKind::Vector => size.bits() == 64 || size.bits() == 128,
};
@@ -43,7 +43,7 @@ fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Opti
}
fn softfloat_float_abi<Ty>(target: &Target, arg: &mut ArgAbi<'_, Ty>) {
if target.abi != Abi::SoftFloat {
if target.rustc_abi != Some(RustcAbi::Softfloat) {
return;
}
// Do *not* use the float registers for passing arguments, as that would make LLVM pick the ABI
+6 -4
View File
@@ -2210,8 +2210,10 @@ pub struct TargetOptions {
pub env: Env,
/// ABI name to distinguish multiple ABIs on the same OS and architecture. For instance, `"eabi"`
/// or `"eabihf"`. Defaults to [`Abi::Unspecified`].
/// This field is *not* forwarded directly to LLVM; its primary purpose is `cfg(target_abi)`.
/// However, parts of the backend do check this field for specific values to enable special behavior.
/// This field is *not* forwarded directly to LLVM and therefore does not control which ABI (in
/// the sense of function calling convention) is actually used; its primary purpose is
/// `cfg(target_abi)`. The actual calling convention is controlled by `llvm_abiname`,
/// `llvm_floatabi`, and `rustc_abi`.
pub abi: Abi,
/// Vendor name to use for conditional compilation (`target_vendor`). Defaults to "unknown".
#[rustc_lint_opt_deny_field_access(
@@ -3228,8 +3230,8 @@ macro_rules! check_matches {
),
RustcAbi::Softfloat => check_matches!(
self.arch,
Arch::X86 | Arch::X86_64 | Arch::S390x,
"`softfloat` ABI is only valid for x86 and s390x targets"
Arch::X86 | Arch::X86_64 | Arch::S390x | Arch::AArch64,
"`softfloat` ABI is only valid for x86, s390x, and aarch64 targets"
),
}
}
@@ -8,13 +8,14 @@
use rustc_abi::Endian;
use crate::spec::{
Abi, Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, StackProbeType,
Target, TargetMetadata, TargetOptions,
Abi, Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, RustcAbi, SanitizerSet,
StackProbeType, Target, TargetMetadata, TargetOptions,
};
pub(crate) fn target() -> Target {
let opts = TargetOptions {
abi: Abi::SoftFloat,
rustc_abi: Some(RustcAbi::Softfloat),
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
features: "+v8a,+strict-align,-neon".into(),
@@ -7,13 +7,14 @@
// For example, `-C target-cpu=cortex-a53`.
use crate::spec::{
Abi, Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, StackProbeType,
Target, TargetMetadata, TargetOptions,
Abi, Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, RustcAbi, SanitizerSet,
StackProbeType, Target, TargetMetadata, TargetOptions,
};
pub(crate) fn target() -> Target {
let opts = TargetOptions {
abi: Abi::SoftFloat,
rustc_abi: Some(RustcAbi::Softfloat),
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
features: "+v8a,+strict-align,-neon".into(),
@@ -1,11 +1,12 @@
use crate::spec::{
Abi, Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, StackProbeType,
Target, TargetMetadata, TargetOptions,
Abi, Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, RustcAbi, SanitizerSet,
StackProbeType, Target, TargetMetadata, TargetOptions,
};
pub(crate) fn target() -> Target {
let opts = TargetOptions {
abi: Abi::SoftFloat,
rustc_abi: Some(RustcAbi::Softfloat),
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
relocation_model: RelocModel::Static,
+16 -12
View File
@@ -5,7 +5,7 @@
use rustc_macros::HashStable_Generic;
use rustc_span::{Symbol, sym};
use crate::spec::{Abi, Arch, FloatAbi, RustcAbi, Target};
use crate::spec::{Arch, FloatAbi, RustcAbi, Target};
/// Features that control behaviour of rustc, rather than the codegen.
/// These exist globally and are not in the target-specific lists below.
@@ -1154,17 +1154,21 @@ pub fn abi_required_features(&self) -> FeatureConstraints {
Arch::AArch64 | Arch::Arm64EC => {
// Aarch64 has no sane ABI specifier, and LLVM doesn't even have a way to force
// the use of soft-float, so all we can do here is some crude hacks.
if self.abi == Abi::SoftFloat {
// LLVM will use float registers when `fp-armv8` is available, e.g. for
// calls to built-ins. The only way to ensure a consistent softfloat ABI
// on aarch64 is to never enable `fp-armv8`, so we enforce that.
// In Rust we tie `neon` and `fp-armv8` together, therefore `neon` is the
// feature we have to mark as incompatible.
FeatureConstraints { required: &[], incompatible: &["neon"] }
} else {
// Everything else is assumed to use a hardfloat ABI. neon and fp-armv8 must be enabled.
// `FeatureConstraints` uses Rust feature names, hence only "neon" shows up.
FeatureConstraints { required: &["neon"], incompatible: &[] }
match self.rustc_abi {
Some(RustcAbi::Softfloat) => {
// LLVM will use float registers when `fp-armv8` is available, e.g. for
// calls to built-ins. The only way to ensure a consistent softfloat ABI
// on aarch64 is to never enable `fp-armv8`, so we enforce that.
// In Rust we tie `neon` and `fp-armv8` together, therefore `neon` is the
// feature we have to mark as incompatible.
FeatureConstraints { required: &[], incompatible: &["neon"] }
}
None => {
// Everything else is assumed to use a hardfloat ABI. neon and fp-armv8 must be enabled.
// `FeatureConstraints` uses Rust feature names, hence only "neon" shows up.
FeatureConstraints { required: &["neon"], incompatible: &[] }
}
Some(r) => panic!("invalid Rust ABI for aarch64: {r:?}"),
}
}
Arch::RiscV32 | Arch::RiscV64 => {