Rollup merge of #151154 - fneddy:s390x_softfloat_abi, r=workingjubilee

Add `s390x-unknown-none-softfloat` with `RustcAbi::Softfloat`

followup on rust-lang/rust#150766

add an `s390x-unknown-none-softfloat` target to use for kernel compilation, as the Linux kernel does not wish to pay the overhead of saving float registers by default on kernel switch. this target's `extern "C"` ABI is unspecified, so it is unstable and subject to change between versions, just like the Linux intrakernel ABI and `extern "Rust"` ABIs are unstable.

enforce target feature incompatibility by adding `RustcAbi::Softfloat`. this is itself just a rename of `RustcAbi::X86Softfloat`, accepting both "x86-softfloat" and "softfloat" as valid strings in the target.json format. the target-features of `"soft-float"` and `"vector"` are incompatible for s390x, so issue a compatibility warning if they are combined.
This commit is contained in:
Jonathan Brouwer 2026-02-09 23:37:48 +01:00 committed by GitHub
commit 1f59a4a86b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 350 additions and 22 deletions

View file

@ -28,7 +28,7 @@ where
BackendRepr::ScalableVector { .. } => panic!("scalable vectors are unsupported"),
BackendRepr::Scalar(scalar) => {
if is_ret && matches!(scalar.primitive(), Primitive::Int(Integer::I128, _)) {
if cx.target_spec().rustc_abi == Some(RustcAbi::X86Softfloat) {
if cx.target_spec().rustc_abi == Some(RustcAbi::Softfloat) {
// Use the native `i128` LLVM type for the softfloat ABI -- in other words, adjust nothing.
} else {
// `i128` is returned in xmm0 by Clang and GCC

View file

@ -76,7 +76,7 @@ macro_rules! target_spec_enum {
pub enum $Name:ident {
$(
$( #[$variant_attr:meta] )*
$Variant:ident = $string:literal,
$Variant:ident = $string:literal $(,$alias:literal)* ,
)*
}
parse_error_type = $parse_error_type:literal;
@ -88,6 +88,7 @@ macro_rules! target_spec_enum {
$(
$( #[$variant_attr] )*
#[serde(rename = $string)] // for JSON schema generation only
$( #[serde(alias = $alias)] )*
$Variant,
)*
}
@ -97,7 +98,10 @@ macro_rules! target_spec_enum {
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
$( $string => Self::$Variant, )*
$(
$string => Self::$Variant,
$($alias => Self::$Variant,)*
)*
_ => {
let all = [$( concat!("'", $string, "'") ),*].join(", ");
return Err(format!("invalid {}: '{s}'. allowed values: {all}", $parse_error_type));
@ -123,7 +127,7 @@ macro_rules! target_spec_enum {
pub enum $Name:ident {
$(
$( #[$variant_attr:meta] )*
$Variant:ident = $string:literal,
$Variant:ident = $string:literal $(,$alias:literal)* ,
)*
}
$( #[$other_variant_attr:meta] )*
@ -134,6 +138,7 @@ macro_rules! target_spec_enum {
pub enum $Name {
$(
$( #[$variant_attr:meta] )*
$( #[serde(alias = $alias)] )*
$Variant,
)*
/// The vast majority of the time, the compiler deals with a fixed
@ -165,7 +170,10 @@ macro_rules! target_spec_enum {
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
$( $string => Self::$Variant, )*
$(
$string => Self::$Variant,
$($alias => Self::$Variant,)*
)*
_ => Self::$OtherVariant(s.to_owned().into()),
})
}

View file

@ -1005,8 +1005,8 @@ crate::target_spec_enum! {
pub enum RustcAbi {
/// On x86-32 only: make use of SSE and SSE2 for ABI purposes.
X86Sse2 = "x86-sse2",
/// On x86-32/64 only: do not use any FPU or SIMD registers for the ABI.
X86Softfloat = "x86-softfloat",
/// On x86-32/64 and S390x: do not use any FPU or SIMD registers for the ABI.
Softfloat = "softfloat", "x86-softfloat",
}
parse_error_type = "rustc abi";
@ -1460,6 +1460,7 @@ supported_targets! {
("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu),
("powerpc64le-unknown-linux-musl", powerpc64le_unknown_linux_musl),
("s390x-unknown-linux-gnu", s390x_unknown_linux_gnu),
("s390x-unknown-none-softfloat", s390x_unknown_none_softfloat),
("s390x-unknown-linux-musl", s390x_unknown_linux_musl),
("sparc-unknown-linux-gnu", sparc_unknown_linux_gnu),
("sparc64-unknown-linux-gnu", sparc64_unknown_linux_gnu),
@ -3204,10 +3205,10 @@ impl Target {
Arch::X86,
"`x86-sse2` ABI is only valid for x86-32 targets"
),
RustcAbi::X86Softfloat => check_matches!(
RustcAbi::Softfloat => check_matches!(
self.arch,
Arch::X86 | Arch::X86_64,
"`x86-softfloat` ABI is only valid for x86 targets"
Arch::X86 | Arch::X86_64 | Arch::S390x,
"`softfloat` ABI is only valid for x86 and s390x targets"
),
}
}

View file

@ -22,7 +22,7 @@ pub(crate) fn target() -> Target {
// If you initialize FP units yourself, you can override these flags with custom linker
// arguments, thus giving you access to full MMX/SSE acceleration.
base.features = "-mmx,-sse,+soft-float".into();
base.rustc_abi = Some(RustcAbi::X86Softfloat);
base.rustc_abi = Some(RustcAbi::Softfloat);
// Turn off DWARF. This fixes an lld warning, "section name .debug_frame is longer than 8
// characters and will use a non-standard string table". That section will not be created if

View file

@ -0,0 +1,39 @@
use rustc_abi::{Align, Endian};
use crate::spec::{
Abi, Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, RustcAbi, SanitizerSet,
StackProbeType, Target, TargetMetadata, TargetOptions,
};
pub(crate) fn target() -> Target {
let opts = TargetOptions {
abi: Abi::SoftFloat,
cpu: "z10".into(),
endian: Endian::Big,
features: "+soft-float,-vector".into(),
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
max_atomic_width: Some(128),
min_global_align: Some(Align::from_bits(16).unwrap()),
panic_strategy: PanicStrategy::Abort,
relocation_model: RelocModel::Static,
rustc_abi: Some(RustcAbi::Softfloat),
stack_probes: StackProbeType::Inline,
supported_sanitizers: SanitizerSet::KERNELADDRESS,
..Default::default()
};
Target {
llvm_target: "s390x-unknown-linux-gnu".into(),
metadata: TargetMetadata {
description: Some("S390x Linux".into()),
host_tools: Some(false),
std: Some(false),
tier: Some(2),
},
arch: Arch::S390x,
data_layout: "E-S64-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64".into(),
options: opts,
pointer_width: 64,
}
}

View file

@ -20,7 +20,7 @@ pub(crate) fn target() -> Target {
relro_level: RelroLevel::Full,
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
rustc_abi: Some(RustcAbi::X86Softfloat),
rustc_abi: Some(RustcAbi::Softfloat),
features: "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,+soft-float".into(),
supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS,
disable_redzone: true,

View file

@ -27,7 +27,7 @@ pub(crate) fn target() -> Target {
// If you initialize FP units yourself, you can override these flags with custom linker
// arguments, thus giving you access to full MMX/SSE acceleration.
base.features = "-mmx,-sse,+soft-float".into();
base.rustc_abi = Some(RustcAbi::X86Softfloat);
base.rustc_abi = Some(RustcAbi::Softfloat);
Target {
llvm_target: "x86_64-unknown-windows".into(),

View file

@ -863,7 +863,7 @@ const IBMZ_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
("miscellaneous-extensions-3", Stable, &[]),
("miscellaneous-extensions-4", Stable, &[]),
("nnp-assist", Stable, &["vector"]),
("soft-float", Forbidden { reason: "currently unsupported ABI-configuration feature" }, &[]),
("soft-float", Forbidden { reason: "unsupported ABI-configuration feature" }, &[]),
("transactional-execution", Unstable(sym::s390x_target_feature), &[]),
("vector", Stable, &[]),
("vector-enhancements-1", Stable, &["vector"]),
@ -1117,7 +1117,7 @@ impl Target {
incompatible: &["soft-float"],
}
}
Some(RustcAbi::X86Softfloat) => {
Some(RustcAbi::Softfloat) => {
// Softfloat ABI, requires corresponding target feature. That feature trumps
// `x87` and all other FPU features so those do not matter.
// Note that this one requirement is the entire implementation of the ABI!
@ -1137,7 +1137,7 @@ impl Target {
incompatible: &["soft-float"],
}
}
Some(RustcAbi::X86Softfloat) => {
Some(RustcAbi::Softfloat) => {
// Softfloat ABI, requires corresponding target feature. That feature trumps
// `x87` and all other FPU features so those do not matter.
// Note that this one requirement is the entire implementation of the ABI!
@ -1237,11 +1237,27 @@ impl Target {
}
}
Arch::S390x => {
// We don't currently support a softfloat target on this architecture.
// As usual, we have to reject swapping the `soft-float` target feature.
// The "vector" target feature does not affect the ABI for floats
// because the vector and float registers overlap.
FeatureConstraints { required: &[], incompatible: &["soft-float"] }
// Same as x86, We use our own ABI indicator here;
// LLVM does not have anything native and will switch ABI based
// on the soft-float target feature.
// Every case should require or forbid `soft-float`!
// The "vector" target feature may only be used without soft-float
// because the float and vector registers overlap and the
// standard s390x C ABI may pass vectors via these registers.
match self.rustc_abi {
None => {
// Default hardfloat ABI.
FeatureConstraints { required: &[], incompatible: &["soft-float"] }
}
Some(RustcAbi::Softfloat) => {
// Softfloat ABI, requires corresponding target feature.
// llvm will switch to soft-float ABI just based on this feature.
FeatureConstraints { required: &["soft-float"], incompatible: &["vector"] }
}
Some(r) => {
panic!("invalid Rust ABI for s390x: {r:?}");
}
}
}
Arch::Avr => {
// SRAM is minimum requirement for C/C++ in both avr-gcc and Clang,

View file

@ -48,6 +48,7 @@ const STAGE0_MISSING_TARGETS: &[&str] = &[
"thumbv6-none-eabi",
"aarch64v8r-unknown-none",
"aarch64v8r-unknown-none-softfloat",
"s390x-unknown-none-softfloat",
];
/// Minimum version threshold for libstdc++ required when using prebuilt LLVM

View file

@ -120,6 +120,7 @@
- [riscv64a23-unknown-linux-gnu](platform-support/riscv64a23-unknown-linux-gnu.md)
- [s390x-unknown-linux-gnu](platform-support/s390x-unknown-linux-gnu.md)
- [s390x-unknown-linux-musl](platform-support/s390x-unknown-linux-musl.md)
- [s390x-unknown-none-softfloat](platform-support/s390x-unknown-none-softfloat.md)
- [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md)
- [solaris](platform-support/solaris.md)
- [\*-nto-qnx-\*](platform-support/nto-qnx.md)

View file

@ -188,6 +188,7 @@ target | std | notes
[`riscv64im-unknown-none-elf`](platform-support/riscv64im-unknown-none-elf.md) | * | Bare RISC-V (RV64IM ISA)
`riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA)
`sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4+, glibc 2.23)
[`s390x-unknown-none-softfloat`](platform-support/s390x-unknown-none-softfloat.md) | * | Bare S390x (softfloat ABI)
[`thumbv6m-none-eabi`](platform-support/thumbv6m-none-eabi.md) | * | Bare Armv6-M
[`thumbv7em-none-eabi`](platform-support/thumbv7em-none-eabi.md) | * | Bare Armv7E-M
[`thumbv7em-none-eabihf`](platform-support/thumbv7em-none-eabi.md) | * | Bare Armv7E-M, hardfloat

View file

@ -0,0 +1,77 @@
# `s390x-unknown-none-softfloat`
**Tier: 2**
IBM z/Architecture (s390x) code in ELF format for kernels, etc.
## Target maintainers
[@uweigand](https://github.com/uweigand)
[@cuviper](https://github.com/cuviper)
## Requirements
This target is intended for kernel development on s390x only. This target is
cross-compiled. There is no support for `std`.There is no default allocator,
but it's possible to use `alloc` by supplying an allocator.
The target does not assume existence of a FPU and does not make use of any
non-GPR register. This allows the generated code to run in environments, such
as kernels, which may need to avoid the use of such registers or which may have
special considerations about the use of such registers (e.g. saving and
restoring them to avoid breaking userspace code using the same registers). You
can change code generation to use additional CPU features via the
`-C target-feature=` codegen options to rustc, or via the `#[target_feature]`
mechanism within Rust code.
By default, code generated with the soft-float target should run on any Z System
starting at [Z10][s390x-isa]. Enabling additional target features or changing the
`-Ctarget-cpu` may raise the ISA required from the `z10` baseline.
`extern "C"` does not use a stable ABI and is subject to change between compiler
or codegen backend versions.
The target only generates object files in the ELF format. Any alternate formats
or special considerations for binary layout will require linker options or linker
scripts.
* [z/Architecture Principles of Operation][s390x-isa]
[s390x-isa]: https://publibfp.dhe.ibm.com/epubs/pdf/a227832d.pdf
[s390x-abi]: https://github.com/IBM/s390x-abi
## Building the target
You can build Rust with support for the target by adding it to the `target`
list in `bootstrap.toml`:
```toml
[build]
target = ["s390x-unknown-none-softfloat"]
```
## Building Rust programs
This target is not intended to build stand-alone binaries. You should only use
it in conjunction with the kernel build toolchain.
## Testing
As code generated by this target is intended to always be part of the kernel,
there are no additional requirements for testing.
If you want to do native testing but do not have your own s390x
machine, there are several options how to get access to one:
* The [IBM LinuxONE Community Cloud][cloud-community] provides a
self-service portal where you can create s390x virtual machine
instances. These are intended for temporary use (limited to 120 days).
* The [IBM LinuxONE Open Source Cloud][cloud-opensource] provides
permanent access to s390x machines. This requires approval by IBM,
which will normally be granted if you're planning to use the machine
to work on an open-source project that is relevant to the IBM Z
ecosystem - the Rust compiler would certainly qualify.
[cloud-community]: https://linuxone.cloud.marist.edu/
[cloud-opensource]: https://community.ibm.com/zsystems/form/l1cc-oss-vm-request/

View file

@ -0,0 +1,64 @@
//@ add-minicore
//@ revisions: enable-softfloat disable-softfloat
//@ assembly-output: emit-asm
//@ compile-flags: -Copt-level=3 --crate-type=lib
//@[enable-softfloat] compile-flags: --target=s390x-unknown-none-softfloat
//@[enable-softfloat] needs-llvm-components: systemz
//@[disable-softfloat] compile-flags: --target=s390x-unknown-linux-gnu
//@[disable-softfloat] needs-llvm-components: systemz
//@ ignore-backends: gcc
#![feature(no_core, lang_items)]
#![no_std]
#![no_core]
extern crate minicore;
use minicore::*;
extern "C" {
fn extern_func(value: f64) -> f64;
}
// CHECK-LABEL: test_softfloat
#[no_mangle]
extern "C" fn test_softfloat() -> f64 {
let value = 3.141_f64;
// without softfloat we load the value direct to the first float register
// we do NOT construct a softfloat in r2 (first non-float arg register)
// disable-softfloat: ld %f{{.*}}, 0(%r{{.*}})
// disable-softfloat-NOT: llihf %r{{.*}}, 1074340036
// disable-softfloat-NOT: oilf %r{{.*}}, 2611340116
// with softfloat we construct the softfloat arg in r2
// we do NOT pass anything by f0 (first float arg register)
// float registers can not be accessed
// enable-softfloat: llihf %r{{.*}}, 1074340036
// enable-softfloat-NEXT: oilf %r{{.*}}, 2611340116
// enable-softfloat-NOT: ld %f{{.*}}, 0(%r{{.*}})
unsafe { extern_func(value) };
// disable-softfloat-NEXT: brasl %r{{.*}}, extern_func@PLT
// enable-softfloat-NEXT: brasl %r{{.*}}, extern_func@PLT
// for return we check that without softfloat we write to float register
// disable-softfloat: ld %f{{.*}}, 0(%r{{.*}})
// disable-softfloat-NOT: llihf %r{{.*}}, 1072841097
// disable-softfloat-NOT: oilf %r{{.*}}, 927712936
#[cfg(not(target_feature = "soft-float"))]
{
1.141_f64
}
// for return we check that WITH softfloat we write to genral purpose register
// enable-softfloat: llihf %r{{.*}}, 1072841097
// enable-softfloat-NEXT: oilf %r{{.*}}, 927712936
// enable-softfloat-NOT: ld %f{{.*}}, 0(%r{{.*}})
#[cfg(target_feature = "soft-float")]
{
2.718_f64
}
// enable-softfloat: br %r{{.*}}
// disable-softfloat: br %r{{.*}}
}

View file

@ -544,6 +544,9 @@
//@ revisions: s390x_unknown_linux_musl
//@ [s390x_unknown_linux_musl] compile-flags: --target s390x-unknown-linux-musl
//@ [s390x_unknown_linux_musl] needs-llvm-components: systemz
//@ revisions: s390x_unknown_none_softfloat
//@ [s390x_unknown_none_softfloat] compile-flags: --target s390x-unknown-none-softfloat
//@ [s390x_unknown_none_softfloat] needs-llvm-components: systemz
//@ revisions: sparc64_unknown_helenos
//@ [sparc64_unknown_helenos] compile-flags: --target sparc64-unknown-helenos
//@ [sparc64_unknown_helenos] needs-llvm-components: sparc

View file

@ -0,0 +1,12 @@
warning: target feature `soft-float` cannot be enabled with `-Ctarget-feature`: unsupported ABI-configuration feature
|
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
warning: target feature `soft-float` must be disabled to ensure that the ABI of the current target can be implemented correctly
|
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
warning: 2 warnings emitted

View file

@ -0,0 +1,7 @@
warning: target feature `vector` must be disabled to ensure that the ABI of the current target can be implemented correctly
|
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
warning: 1 warning emitted

View file

@ -0,0 +1,38 @@
//@ add-minicore
//@ revisions: disable-softfloat enable-softfloat
//@ assembly-output: emit-asm
//@ compile-flags: -Copt-level=3 --crate-type=lib
// we expect the build to fail in the feature
//@ build-pass
//@ [enable-softfloat] compile-flags: --target=s390x-unknown-none-softfloat
//@ [enable-softfloat] compile-flags: -C target-feature=+vector
//@ [enable-softfloat] needs-llvm-components: systemz
//@ [disable-softfloat] compile-flags: --target=s390x-unknown-linux-gnu
//@ [disable-softfloat] compile-flags: -C target-feature=+soft-float
//@ [disable-softfloat] needs-llvm-components: systemz
//@ ignore-backends: gcc
//[disable-softfloat]~? WARN target feature `soft-float` must be disabled to ensure that the ABI of the current target can be implemented correctly
//[disable-softfloat]~? WARN target feature `soft-float` cannot be enabled with `-Ctarget-feature`
//[enable-softfloat]~? WARN target feature `vector` must be disabled to ensure that the ABI of the current target can be implemented correctly
#![feature(no_core, lang_items)]
#![no_std]
#![no_core]
extern crate minicore;
use minicore::*;
extern "C" {
fn extern_func(value: f64) -> f64;
}
#[no_mangle]
extern "C" fn test_softfloat() -> f64 {
let value = 3.141_f64;
unsafe { extern_func(value) } ;
2.718_f64
}

View file

@ -1,4 +1,4 @@
warning: target feature `soft-float` cannot be enabled with `-Ctarget-feature`: currently unsupported ABI-configuration feature
warning: target feature `soft-float` cannot be enabled with `-Ctarget-feature`: unsupported ABI-configuration feature
|
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>

View file

@ -0,0 +1,8 @@
//@ add-minicore
//@ no-prefer-dynamic
//@ compile-flags: --target=s390x-unknown-linux-gnu
//@ needs-llvm-components: systemz
#![feature(no_core)]
#![crate_type = "rlib"]
#![no_core]

View file

@ -0,0 +1,8 @@
//@ add-minicore
//@ no-prefer-dynamic
//@ compile-flags: --target=s390x-unknown-none-softfloat
//@ needs-llvm-components: systemz
#![feature(no_core)]
#![crate_type = "rlib"]
#![no_core]

View file

@ -0,0 +1,12 @@
error[E0461]: couldn't find crate `enabled_softfloat` with expected target triple s390x-unknown-linux-gnu
--> $DIR/incompatible_softfloat_targets.rs:17:1
|
LL | extern crate enabled_softfloat;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the following crate versions were found:
crate `enabled_softfloat`, target triple s390x-unknown-none-softfloat: $TEST_BUILD_DIR/auxiliary/libenabled_softfloat.rlib
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0461`.

View file

@ -0,0 +1,12 @@
error[E0461]: couldn't find crate `disabled_softfloat` with expected target triple s390x-unknown-none-softfloat
--> $DIR/incompatible_softfloat_targets.rs:19:1
|
LL | extern crate disabled_softfloat;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the following crate versions were found:
crate `disabled_softfloat`, target triple s390x-unknown-linux-gnu: $TEST_BUILD_DIR/auxiliary/libdisabled_softfloat.rlib
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0461`.

View file

@ -0,0 +1,20 @@
//@ add-minicore
//@ aux-build: disabled_softfloat.rs
//@ aux-build: enabled_softfloat.rs
//@ revisions: disable-softfloat enable-softfloat
//@ check-fail
//@ [enable-softfloat] compile-flags: --target=s390x-unknown-none-softfloat
//@ [enable-softfloat] needs-llvm-components: systemz
//@ [disable-softfloat] compile-flags: --target=s390x-unknown-linux-gnu
//@ [disable-softfloat] needs-llvm-components: systemz
//@ ignore-backends: gcc
#![feature(no_core)]
#![crate_type = "rlib"]
#![no_core]
extern crate enabled_softfloat;
//[disable-softfloat]~^ ERROR couldn't find crate `enabled_softfloat` with expected target triple s390x-unknown-linux-gnu
extern crate disabled_softfloat;
//[enable-softfloat]~^ ERROR couldn't find crate `disabled_softfloat` with expected target triple s390x-unknown-none-softfloat